Важно понимать, что на самом деле это оболочка, которая расширяет ее foo*до списка совпадающих имен файлов, поэтому мало что mvможет сделать сам.
Проблема здесь в том, что когда глобус не совпадает, некоторые оболочки bash(и большинство других подобных Борну оболочек, такое ошибочное поведение было фактически введено оболочкой Борна в конце 70-х) дословно передают шаблон в команду.
Таким образом, здесь, когда foo*не совпадает ни один файл, вместо прерывания команды (как это делают оболочки до Борна и несколько современных оболочек), оболочка передает дословный foo*файл mv, поэтому в основном запрашивается mvперемещение вызываемого файла foo*.
Этот файл не существует. Если бы это было так, это действительно соответствовало бы шаблону, поэтому mvвыдает ошибку. Если шаблон был foo[xy]вместо этого, mvмог бы случайно переместить файл с именем foo[xy]вместо fooxи fooyфайлов.
Теперь, даже в тех оболочках, у которых нет этой проблемы (pre-Bourne, csh, tcsh, fish, zsh, bash -O failglob), вы все равно получите сообщение об ошибке mv foo* ~/bar, но на этот раз от оболочки.
Если вы хотите считать это не ошибкой, если нет соответствия файлов foo*и в этом случае ничего не перемещать, сначала нужно создать список файлов (таким образом, чтобы не вызывать ошибку, например, с помощью nullglobпараметра некоторые снаряды), и тогда только вызов mvэто список не пустой.
Это было бы лучше, чем скрывать все ошибки mv(как при добавлении 2> /dev/null), как если бы произошел mvсбой по любой другой причине, вы, вероятно, все равно захотите узнать, почему.
в зш
files=(foo*(N)) # where the N glob qualifier activates nullglob for that glob
(($#files == 0)) || mv -- $files ~/bar/
Или используйте анонимную функцию, чтобы избежать использования временной переменной:
() { (($# == 0)) || mv -- "$@" ~/bar/; } foo*(N)
zshэто одна из тех оболочек, которые не имеют ошибки Борна и сообщают об ошибке, не выполнив команду, когда глобус не совпадает (и nullglobопция не была включена), поэтому здесь вы можете скрыть zshошибку и восстановить для stderr, mvтак что вы все равно увидите mvошибки, если они есть, но не ошибки о несоответствующих глобусах:
(mv 2>&3 foo* ~/bar/) 3>&2 2>&-
Или вы можете использовать, zargsчто также позволит избежать проблем, если foo*глобус будет расширяться до слишком больших файлов.
autoload zargs # best in ~/.zshrc
zargs -r -- foo* -- mv -t ~/bar # here assuming GNU mv for its -t option
В кш93:
files=(~(N)foo*)
((${#files[#]} == 0)) || mv -- "${files[@]}" ~/bar/
В Баш:
bashне имеет синтаксиса для включения только nullglobдля одного глобуса, и failglobопция отменяется, nullglobпоэтому вам понадобятся такие вещи, как:
saved=$(shopt -p nullglob failglob) || true
shopt -s nullglob
shopt -u failglob
files=(foo*)
((${#files[@]} == 0)) || mv -- "${files[@]}" ~/bar/
eval "$saved"
или установить параметры в подоболочке для сохранения, чтобы сохранить их до, а затем восстановить их.
(
shopt -s nullglob
shopt -u failglob
files=(foo*)
((${#files[@]} == 0)) || mv -- "${files[@]}" ~/bar/
)
В yash
(
set -o nullglob
files=(foo*)
[ "${#files[@]}" -eq 0 ] || mv -- "${files[@]}" ~/bar/
)
В fish
В оболочке fish поведение nullglob является значением по умолчанию для setкоманды, поэтому оно просто:
set files foo*
count $files > /dev/null; and mv -- $files ~/bar/
POSIXly
Там нет nullglobопции в POSIX shи нет массива, кроме позиционных параметров. Есть способ, который вы можете использовать для определения соответствия шара или нет:
set -- foo[*] foo*
if [ "$1$2" != 'foo[*]foo*' ]; then
shift
mv -- "$@" ~/bar/
fi
Используя как a, так foo[*]и foo*glob, мы можем различить случай, когда нет соответствующего файла, и случай, когда есть один файл, который вызван foo*(что set -- foo*не может сделать).
Больше чтения:
mv foo* ~/bar/ 2> /dev/null?