
function mv1 { mv -n "$1" "targetdir" -v |wc -l ;}
mv1 *.png
Es verschiebt nur die erste .png
gefundene Datei, nicht alle.
Wie kann ich den Befehl auf alle Dateien anwenden, die mit den Platzhaltern übereinstimmen?
Antwort1
mv1 *.png
erweitert zuerst das Platzhaltermuster *.png
in die Liste der übereinstimmenden Dateinamen und übergibt dann diese Liste der Dateinamen an die Funktion.
Innerhalb der Funktion $1
bedeutet das: Nehmen Sie das erste Argument der Funktion, teilen Sie es dort auf, wo es Leerzeichen enthält, und ersetzen Sie alle durch Leerzeichen getrennten Teile, die Platzhalterzeichen enthalten und mindestens einem Dateinamen entsprechen, durch die Liste der übereinstimmenden Dateinamen. Klingt kompliziert? Das ist es auch, und dieses Verhalten ist nur gelegentlich nützlich und oft problematisch. Dieses Aufteilungs- und Übereinstimmungsverhalten tritt nur auf, wenn $1
es außerhalb von doppelten Anführungszeichen auftritt, daher ist die Lösung einfach: Verwenden Sie doppelte Anführungszeichen.Setzen Sie Variablensubstitutionen immer in Anführungszeichen.es sei denn, Sie haben einen guten Grund, dies nicht zu tun.
Wenn das aktuelle Verzeichnis beispielsweise die beiden Dateien A* algorithm.png
und enthält graph1.png
, wird als erstes Argument und als zweites Argument an die Funktion mv1 *.png
übergeben . Dann wird in und aufgeteilt . Das Muster entspricht und enthält keine Platzhalterzeichen. Daher wird die Funktion letztendlich mit den Argumenten , , , und ausgeführt . Wenn Sie die Funktion korrigieren zuA* algorithm.png
graph1.png
$1
A*
algorithm.png
A*
A* algorithm.png
algorithm.png
mv
-n
A* algorithm.png
algorithm.png
targetdir
-v
function mv1 { mv -n "$1" "targetdir" -v |wc -l ;}
dann wird die erste Datei korrekt verschoben.
Herstellenalledie Argumente, weisen Sie die Shell an, alle Argumente zu verarbeiten und nicht nur das erste. Sie können verwenden, "$@"
um die vollständige Liste der an die Funktion übergebenen Argumente anzugeben.
function mv1 { mv -n "$@" "targetdir" -v |wc -l ;}
Dies ist fast korrekt, schlägt aber trotzdem fehl, wenn ein Dateiname mit dem Zeichen beginnt -
, weil mv
dieses Argument als Option behandelt wird. Übergeben Sie --
es an mv
, um ihm mitzuteilen „ab diesem Punkt keine weiteren Optionen mehr“. Dies ist eine sehr gängige Konvention, die von den meisten Befehlen unterstützt wird.
function mv1 { mv -n -v -- "$@" "targetdir" |wc -l ;}
Ein verbleibendes Problem ist mv
, dass diese Funktion im Fehlerfall einen Erfolgsstatus zurückgibt, da der Beendigungsstatus von Befehlen auf der linken Seite einer Pipe ignoriert wird. In Bash (oder KSH) können Sie verwenden, set -o pipefail
um die Pipeline zum Scheitern zu bringen. Beachten Sie, dass das Setzen dieser Option dazu führen kann, dass anderer Code, der in derselben Shell ausgeführt wird, fehlschlägt. Sie sollten sie daher lokal in der Funktion setzen, was seit Bash 4.4 möglich ist.
function mv1 {
local -
set -o pipefail
mv -n -v -- "$@" "targetdir" | wc -l
}
In früheren Versionen pipefail
war die Einstellung fehleranfällig, daher wäre es besser, sie PIPESTATUS
stattdessen explizit zu prüfen.
function mv1 {
mv -n -v -- "$@" "targetdir" | wc -l
((!${PIPESTATUS[0] && !${PIPESTATUS[1]}}))
}
Antwort2
$1
ist das erste Argument der Funktion, hier die erste Datei, die übereinstimmt *.png
. Ich vermute, das "$@"
ist es, was Sie anstelle von verwenden möchten $1
.
Antwort3
Sie müssten verwenden mv1 \*.png
.
Bei der Interaktion mit Funktionen übergibt das Linux-Terminal das Asterisk nicht direkt an den Befehl, sondern wählt den ersten passenden Parameter aus und übergibt diesen an den Befehl.
Um das Sternchen direkt durchzulassen, muss man es mit einem Backslash maskieren.