Ważne jest, aby zdać sobie sprawę, że tak naprawdę to powłoka rozszerza foo*ją na listę pasujących nazw plików, więc niewiele mvmożna zrobić.
Problem polega na tym, że gdy glob nie pasuje, niektóre powłoki takie jak bash(i większość innych powłok podobnych do Bourne'a, to zachowanie błędne zostało wprowadzone przez powłokę Bourne'a pod koniec lat 70.) przekazują wzorzec dosłownie do polecenia.
Więc tutaj, gdy foo*nie pasuje do żadnego pliku, zamiast przerywać polecenie (jak robią to wcześniejsze powłoki Bourne'a i kilka nowoczesnych powłok), powłoka przekazuje foo*plik dosłowny mv, więc w zasadzie prosi mvo przeniesienie pliku o nazwie foo*.
Ten plik nie istnieje. Gdyby tak było, rzeczywiście pasowałby do wzorca, więc mvzgłasza błąd. Gdyby foo[xy]zamiast tego wzorzec , mvmógł przypadkowo przenieść plik o nazwie foo[xy]zamiast plików fooxi fooy.
Teraz nawet w tych powłokach, które nie mają tego problemu (przed Bourne, csh, tcsh, fish, zsh, bash -O failglob), nadal pojawiał się błąd mv foo* ~/bar, ale tym razem przez powłokę.
Jeśli chcesz uznać to za błąd, jeśli nie ma pasującego pliku, foo*a w takim przypadku nie przenosić niczego, najpierw musisz zbudować listę plików (w sposób, który nie powoduje błędu, jak przy użyciu nullglobopcji niektóre muszle), a następnie tylko wywołanie mvjest takie, że lista nie jest pusta.
Byłoby to lepsze niż ukrywanie wszystkich błędów mv(tak jak w przypadku dodawania 2> /dev/null), jak gdyby mvnie powiodło się z jakiegokolwiek innego powodu, prawdopodobnie nadal chcesz wiedzieć, dlaczego.
w Zsh
files=(foo*(N)) # where the N glob qualifier activates nullglob for that glob
(($#files == 0)) || mv -- $files ~/bar/
Lub użyj funkcji anonimowej, aby uniknąć używania zmiennej tymczasowej:
() { (($# == 0)) || mv -- "$@" ~/bar/; } foo*(N)
zshjest jedną z tych powłok, które nie zawierają błędu Bourne'a i zgłaszają błąd bez wykonania polecenia, gdy glob nie pasuje (a nullglobopcja nie została włączona), więc tutaj możesz ukryć zshbłąd i przywrócić stderr dla, mvwięc nadal będziesz widzieć mvbłędy, jeśli takie istnieją, ale nie błąd dotyczący niepasujących globów:
(mv 2>&3 foo* ~/bar/) 3>&2 2>&-
Lub możesz użyć tego, zargsco uniknęłoby również problemów, gdyby foo*glob rozszerzył się do zbyt dużych plików.
autoload zargs # best in ~/.zshrc
zargs -r -- foo* -- mv -t ~/bar # here assuming GNU mv for its -t option
W ksh93:
files=(~(N)foo*)
((${#files[#]} == 0)) || mv -- "${files[@]}" ~/bar/
W bash:
bashnie ma składni, aby włączyć tylko nullglobdla jednego globu, a failglobopcja anuluje, nullglobwięc potrzebujesz takich rzeczy jak:
saved=$(shopt -p nullglob failglob) || true
shopt -s nullglob
shopt -u failglob
files=(foo*)
((${#files[@]} == 0)) || mv -- "${files[@]}" ~/bar/
eval "$saved"
lub ustaw opcje w podpowłoce, aby zapisać trzeba je wcześniej zapisać, a następnie przywrócić.
(
shopt -s nullglob
shopt -u failglob
files=(foo*)
((${#files[@]} == 0)) || mv -- "${files[@]}" ~/bar/
)
W yash
(
set -o nullglob
files=(foo*)
[ "${#files[@]}" -eq 0 ] || mv -- "${files[@]}" ~/bar/
)
W fish
W skorupce ryby zachowanie nullglob jest domyślnym setpoleceniem, więc jest to po prostu:
set files foo*
count $files > /dev/null; and mv -- $files ~/bar/
POSIXly
W nullglobPOSIX shnie ma opcji ani tablicy innej niż parametry pozycyjne. Istnieje jednak sztuczka, której można użyć do wykrycia, czy glob pasuje, czy nie:
set -- foo[*] foo*
if [ "$1$2" != 'foo[*]foo*' ]; then
shift
mv -- "$@" ~/bar/
fi
Używając zarówno a, jak foo[*]i foo*glob, możemy rozróżnić przypadek, w którym nie ma pasującego pliku, i ten, w którym jest jeden plik, który jest wywoływany foo*(czego set -- foo*nie można zrobić).
Więcej lektur:
mv foo* ~/bar/ 2> /dev/null?