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 mv
tun 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 mv
genannt , 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 mv
ein Fehler gemeldet wird. Wäre das Muster foo[xy]
stattdessen gewesen, mv
hätte man versehentlich eine aufgerufene Datei foo[xy]
anstelle der foox
und 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* ~/bar
diesmal 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 nullglob
Option von einige Muscheln), und dann nur aufrufen, mv
ist die Liste nicht leer.
Das wäre besser, als alle Fehler zu verbergen mv
(als 2> /dev/null
würde das Hinzufügen ), als ob mv
es 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)
zsh
ist 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 nullglob
Option nicht aktiviert wurde). Hier können Sie also den zsh
Fehler ausblenden und wiederherstellen stderr für mv
so würden Sie immer noch die mv
Fehler 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, zargs
was 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:
bash
Es gibt keine Syntax, die nur nullglob
für einen Glob aktiviert werden kann , und die failglob
Option wird deaktiviert, nullglob
sodass 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 set
Befehl.
set files foo*
count $files > /dev/null; and mv -- $files ~/bar/
POSIXly
nullglob
In POSIX gibt es keine Option sh
und 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
?