Важливо усвідомити, що насправді оболонка розширює foo*їх до списку відповідних імен файлів, тому мало що mvможе зробити сама.
Проблема тут полягає в тому, що коли глобус не відповідає, деякі снаряди на зразок bash(і більшість інших оболонок, подібних до Борна, таку баггічну поведінку насправді впроваджувала оболонка Борна в кінці 70-х років) передають шаблон дослівно в команду.
Тож тут, коли foo*не відповідає жодному файлу, замість того, щоб скасувати команду (як, наприклад, оболонки перед Борном та декілька сучасних оболонок), оболонка передає дослівний foo*файл mv, тому в основному просить mvперемістити названий файл foo*.
Цей файл не існує. Якби це було, воно фактично відповідало б шаблону, тому mvповідомляє про помилку. Якби шаблон був foo[xy]замість цього, ви mvмогли б випадково перемістити файл, названий foo[xy]замість файлів fooxта fooyфайлів.
Тепер, навіть у тих оболонках, які не мають цієї проблеми (до Борна, csh, tcsh, риби, 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є однією з тих оболонок, у яких немає помилки Bourne і повідомляють про помилку, не виконуючи команду, коли глобус не відповідає (а nullglobпараметр не ввімкнено), тож тут ви можете приховати zshпомилку та відновити stderr for, mvтому ви все одно побачите mvпомилки, якщо такі є, але не помилку щодо невідповідних глобусів:
(mv 2>&3 foo* ~/bar/) 3>&2 2>&-
Або ви можете використовувати, zargsщо також уникне проблем, якщо foo*глобус розшириться на занадто man файли.
autoload zargs # best in ~/.zshrc
zargs -r -- foo* -- mv -t ~/bar # here assuming GNU mv for its -t option
У ksh93:
files=(~(N)foo*)
((${#files[#]} == 0)) || mv -- "${files[@]}" ~/bar/
В bash:
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
У рибній оболонці поведінка nullglob є типовою для setкоманди, тому це просто:
set files foo*
count $files > /dev/null; and mv -- $files ~/bar/
POSIXly
У nullglobPOSIX 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?