Es ist wichtig zu wissen , dass es tatsächlich die Shell ist, die das foo*auf die Liste der übereinstimmenden Dateinamen erweitert, so dass sich selbst wenig mvtun kann.
Das Problem hierbei ist, dass, wenn ein Glob nicht übereinstimmt, einige Shells bash(und die meisten anderen Bourne-ähnlichen Shells, die in den späten 70er Jahren von der Bourne-Shell eingeführt wurden) das Muster wörtlich an den Befehl übergeben.
Also hier, wenn foo*keine Datei entspricht, anstatt den Befehl Abbruch (wie Pre-Bourne - Shells und mehrere modernen Schalen tun), so geht die Schale eine wortgetreue foo*Datei auf mv, so dass im Grunde fragt mvgenannt , die Datei zu bewegen foo*.
Diese Datei existiert nicht. Wenn dies der Fall wäre, hätte es tatsächlich mit dem Muster überein- gestimmt, sodass mvein Fehler gemeldet wird. Wäre das Muster foo[xy]stattdessen gewesen, mvhätte man versehentlich eine aufgerufene Datei foo[xy]anstelle der fooxund fooy-Dateien verschieben können.
Selbst in Shells, die dieses Problem nicht haben (vor Bourne, csh, tcsh, fish, zsh, bash -O failglob), wird immer noch ein Fehler angezeigt, mv foo* ~/bardiesmal jedoch von der Shell.
Wenn Sie möchten, dass es kein Fehler ist, wenn keine Datei gefunden wurde, foo*und in diesem Fall nichts verschieben möchten, sollten Sie zuerst die Liste der Dateien erstellen (auf eine Weise, die keinen Fehler verursacht, wie mit der nullglobOption von einige Muscheln), und dann nur aufrufen, mvist die Liste nicht leer.
Das wäre besser, als alle Fehler zu verbergen mv(als 2> /dev/nullwürde das Hinzufügen ), als ob mves aus irgendeinem anderen Grund fehlschlagen würde. Sie würden wahrscheinlich immer noch wissen wollen, warum.
in zsh
files=(foo*(N)) # where the N glob qualifier activates nullglob for that glob
(($#files == 0)) || mv -- $files ~/bar/
Oder verwenden Sie eine anonyme Funktion, um die Verwendung einer temporären Variablen zu vermeiden:
() { (($# == 0)) || mv -- "$@" ~/bar/; } foo*(N)
zshist eine dieser Shells, die den Bourne-Fehler nicht aufweisen und einen Fehler melden, ohne den Befehl auszuführen, wenn ein Glob nicht übereinstimmt (und die nullglobOption nicht aktiviert wurde). Hier können Sie also den zshFehler ausblenden und wiederherstellen stderr für mvso würden Sie immer noch die mvFehler sehen, wenn überhaupt, aber nicht den Fehler über die nicht passenden Globs:
(mv 2>&3 foo* ~/bar/) 3>&2 2>&-
Oder Sie könnten verwenden, zargswas auch Probleme vermeiden foo*würde, wenn der Glob zu man-Dateien erweitern würde.
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 der Bash:
bashEs gibt keine Syntax, die nur nullglobfür einen Glob aktiviert werden kann , und die failglobOption wird deaktiviert, nullglobsodass Sie Folgendes benötigen:
saved=$(shopt -p nullglob failglob) || true
shopt -s nullglob
shopt -u failglob
files=(foo*)
((${#files[@]} == 0)) || mv -- "${files[@]}" ~/bar/
eval "$saved"
oder setzen Sie die Optionen in einer Subshell, um sie zu speichern, bevor Sie sie speichern und anschließend wiederherstellen müssen.
(
shopt -s nullglob
shopt -u failglob
files=(foo*)
((${#files[@]} == 0)) || mv -- "${files[@]}" ~/bar/
)
Im yash
(
set -o nullglob
files=(foo*)
[ "${#files[@]}" -eq 0 ] || mv -- "${files[@]}" ~/bar/
)
Im fish
In der Fish Shell ist das Nullglob-Verhalten die Standardeinstellung für den setBefehl.
set files foo*
count $files > /dev/null; and mv -- $files ~/bar/
POSIXly
nullglobIn POSIX gibt es keine Option shund kein Array außer den Positionsparametern. Es gibt jedoch einen Trick, mit dem Sie feststellen können, ob ein Glob übereinstimmt oder nicht:
set -- foo[*] foo*
if [ "$1$2" != 'foo[*]foo*' ]; then
shift
mv -- "$@" ~/bar/
fi
Wenn Sie sowohl a foo[*]als auch foo*glob verwenden, können Sie zwischen dem Fall, in dem es keine übereinstimmende Datei gibt, und dem Fall, in dem es eine Datei gibt, die zufällig aufgerufen wird foo*(was ein set -- foo*nicht tun kann), unterscheiden.
Lesen Sie weiter:
mv foo* ~/bar/ 2> /dev/null?