È importante rendersi conto che in realtà è la shell che lo espande foo*all'elenco dei nomi di file corrispondenti, quindi c'è poco che mvpotrebbe fare da solo.
Il problema qui è che quando un glob non corrisponde, alcune shell come bash(e la maggior parte delle altre shell Bourne-like, quel comportamento buggy è stato effettivamente introdotto dalla shell Bourne alla fine degli anni '70) passano il pattern alla lettera al comando.
Quindi qui, quando foo*non corrisponde a nessun file, invece di interrompere il comando (come fanno le shell pre-Bourne e diverse shell moderne), la shell passa un foo*file testuale a mv, quindi sostanzialmente chiede mvdi spostare il file chiamato foo*.
Quel file non esiste. In tal caso, avrebbe effettivamente adattato il modello, quindi mvsegnala un errore. Se il modello fosse stato foo[xy]invece, mvavrebbe potuto spostare accidentalmente un file chiamato al foo[xy]posto dei file fooxe fooy.
Ora, anche in quelle shell che non hanno questo problema (pre-Bourne, csh, tcsh, fish, zsh, bash -O failglob), avresti ancora un errore mv foo* ~/bar, ma questa volta dalla shell.
Se vuoi considerarlo non un errore se non c'è corrispondenza dei file foo*e in quel caso, non spostare nulla, ti consigliamo di costruire prima l'elenco dei file (in un modo che non causi un errore come usando l' nullglobopzione di alcune shell), quindi solo call mvè l'elenco non vuoto.
Sarebbe meglio che nascondere tutti gli errori di mv(come 2> /dev/nullfarebbe l' aggiunta ) come se mvfallissero per qualsiasi altra ragione, probabilmente vorrai comunque sapere perché.
in zsh
files=(foo*(N)) # where the N glob qualifier activates nullglob for that glob
(($#files == 0)) || mv -- $files ~/bar/
Oppure usa una funzione anonima per evitare di usare una variabile temporanea:
() { (($# == 0)) || mv -- "$@" ~/bar/; } foo*(N)
zshè una di quelle shell che non hanno il bug Bourne e riportano un errore senza eseguire il comando quando un glob non corrisponde (e l' nullglobopzione non è stata abilitata), quindi qui puoi nascondere zshl'errore e ripristinare stderr per mvcosì vedresti ancora gli mveventuali errori, ma non l'errore relativo ai globs non corrispondenti:
(mv 2>&3 foo* ~/bar/) 3>&2 2>&-
Oppure potresti usare zargsciò che eviterebbe anche problemi se il foo*glob si espandesse in file troppo man.
autoload zargs # best in ~/.zshrc
zargs -r -- foo* -- mv -t ~/bar # here assuming GNU mv for its -t option
In ksh93:
files=(~(N)foo*)
((${#files[#]} == 0)) || mv -- "${files[@]}" ~/bar/
In bash:
bashnon ha sintassi da abilitare nullglobper un solo glob, e l' failglobopzione annulla nullglobquindi avresti bisogno di cose come:
saved=$(shopt -p nullglob failglob) || true
shopt -s nullglob
shopt -u failglob
files=(foo*)
((${#files[@]} == 0)) || mv -- "${files[@]}" ~/bar/
eval "$saved"
oppure impostare le opzioni in una subshell per salvare devono salvarle prima e ripristinarle successivamente.
(
shopt -s nullglob
shopt -u failglob
files=(foo*)
((${#files[@]} == 0)) || mv -- "${files[@]}" ~/bar/
)
Nel yash
(
set -o nullglob
files=(foo*)
[ "${#files[@]}" -eq 0 ] || mv -- "${files[@]}" ~/bar/
)
Nel fish
Nella shell di pesce, il comportamento nullglob è il valore predefinito per il setcomando, quindi è solo:
set files foo*
count $files > /dev/null; and mv -- $files ~/bar/
POSIXly
Non esiste alcuna nullglobopzione in POSIX she nessun array oltre ai parametri posizionali. C'è un trucco che puoi usare per rilevare se un glob corrisponde o meno:
set -- foo[*] foo*
if [ "$1$2" != 'foo[*]foo*' ]; then
shift
mv -- "$@" ~/bar/
fi
Usando sia a foo[*]che foo*glob, possiamo distinguere tra il caso in cui non esiste un file corrispondente e quello in cui esiste un file che sembra essere chiamato foo*(cosa che set -- foo*non si può fare).
Più lettura:
mv foo* ~/bar/ 2> /dev/null?