Важно понимать, что на самом деле это оболочка, которая расширяет ее 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
?