Ich bin auf dieses Skript gestoßen:
#! /bin/bash
if (( $# < 3 )); then
echo "$0 old_string new_string file [file...]"
exit 0
else
ostr="$1"; shift
nstr="$1"; shift
fi
echo "Replacing \"$ostr\" with \"$nstr\""
for file in $@; do
if [ -f $file ]; then
echo "Working with: $file"
eval "sed 's/"$ostr"/"$nstr"/g' $file" > $file.tmp
mv $file.tmp $file
fi
done
Welche Bedeutung haben die Zeilen, in denen sie verwendet werden shift
? Ich nehme an, das Skript sollte zumindest mit Argumenten verwendet werden, also ...?
shell-script
arguments
Patryk
quelle
quelle
pushd
undpopd
).bash
, ist die Frage für alle Shells allgemein, daher gilt der Posix-Standard: pubs.opengroup.org/onlinepubs/9699919799/utilities/…Wie der Kommentar von Goldlöckchen und die Referenzen der Menschheit beschreiben, werden
shift
die Positionsparameter ($1
,$2
usw.) neu zugewiesen , sodass$1
der alte Wert von$2
,$2
der Wert von$3
usw. übernommen wird. * Der alte Wert von$1
wird verworfen. ($0
wird nicht geändert.) Einige Gründe dafür sind:$10
funktioniert nicht - es wird als$1
verkettet mit einem interpretiert0
(und könnte so etwas produzierenHello0
). Nach ashift
wird das zehnte Argument$9
. (In den meisten modernen Shells können Sie jedoch verwenden${10}
.)for
ist viel besser dafür.$1
und$2
Textzeichenfolgen, während$3
und alle anderen Parameter Dateinamen sind.So spielt es sich ab. Angenommen, Ihr Skript wird aufgerufen
Patryk_script
und heißtDas Skript sieht
Die Anweisung
ostr="$1"
setzt die Variableostr
aufUSSR
. Die ersteshift
Anweisung ändert die Positionsparameter wie folgt:Die Anweisung
nstr="$1"
setzt die Variablenstr
aufRussia
. Die zweiteshift
Anweisung ändert die Positionsparameter wie folgt:Und dann die
for
Schleife ÄnderungenUSSR
($ostr
) zuRussia
($nstr
) in den AktenTreaty1
,Atlas2
undPravda3
.Es gibt einige Probleme mit dem Skript.
Wenn das Skript als aufgerufen wird
es sieht
aber, weil
$@
nicht zitiert wird, in dem RaumWorld Atlas2
ist nicht in Anführungszeichen gesetzt, und diefor
Schleife denkt , dass es vier Dateien hat:Treaty1
,World
,Atlas2
, undPravda3
. Dies sollte auch so sein(um Sonderzeichen in den Argumenten zu zitieren) oder einfach
(was der längeren Version entspricht).
Dies ist nicht unbedingt erforderlich
eval
, und die Weitergabe ungeprüfter Benutzereingaben aneval
kann gefährlich sein. Zum Beispiel, wenn das Skript als aufgerufen wirdes wird ausgeführt
rm *
! Dies ist ein großes Problem, wenn das Skript mit höheren Berechtigungen ausgeführt werden kann als die des Benutzers, der es aufruft. Zum Beispiel, wenn es übersudo
eine Weboberfläche ausgeführt oder von dieser aufgerufen werden kann. Es ist wahrscheinlich nicht so wichtig, wenn Sie es nur als Sie selbst in Ihrem Verzeichnis verwenden. Aber es kann geändert werdenDies birgt immer noch einige Risiken, die jedoch viel weniger schwerwiegend sind.
if [ -f $file ]
,> $file.tmp
Undmv $file.tmp $file
sollte es seinif [ -f "$file" ]
,> "$file.tmp"
undmv "$file.tmp" "$file"
jeweils mit Dateinamen umgehen , die Leerzeichen (oder andere lustige Zeichen) in ihnen haben könnte. (Mit demeval "sed …
Befehl werden auch Dateinamen mit Leerzeichen entstellt.)*
shift
akzeptiert ein optionales Argument: eine positive Ganzzahl, die angibt, wie viele Parameter verschoben werden sollen. Der Standardwert ist eins (1
). Zum Beispielshift 4
verursacht$5
zu werden$1
,$6
zu werden$2
und so weiter. (Beachten Sie, dass das Beispiel im Bash-Handbuch für Anfänger falsch ist.) Daher kann Ihr Skript geändert werdenwas als klarer angesehen werden könnte.
Endnote / Warnung:
Die Windows-Eingabeaufforderungssprache (Batch-Datei) unterstützt auch einen
SHIFT
Befehl, der im Grunde das Gleiche wie dershift
Befehl in Unix-Shells tut , mit einem auffälligen Unterschied, den ich verstecke, um zu verhindern, dass die Benutzer dadurch verwirrt werden:quelle
shift
kann aufwhile
,until
und sogar auffor
Schleifen angewendet werden , um Arrays auf viel subtilere Weise zu handhaben als eine einfachefor
Schleife. Ich finde es oft nützlich infor
Loops wie ...set -f -- $args; IFS=$split; for arg do set -- $arg; shift "${number_of_fields_to_discard}" && fn_that_wants_split_arg "$arg"; done
Die einfachste Erklärung ist dies. Betrachten Sie den Befehl:
Ohne die Hilfe von können
shift
Sie nicht den vollständigen Wert des Standorts extrahieren, da dieser Wert beliebig lang werden kann. Wenn Sie zweimal verschieben, werden die ArgumenteSET
undlocation
so entfernt, dass:Betrachte das
$@
Ding sehr lange . Dies bedeutet, dass der gesamte Ortx
trotz der Leerzeichen und Kommas in einer Variablen gespeichert werden kann. Zusammenfassend rufen wir also aufshift
und rufen später den Wert dessen ab, was von der Variablen übrig bleibt$@
.UPDATE Ich füge unten ein sehr kurzes Snippet hinzu, das das Konzept und den Nutzen von zeigt,
shift
ohne das es sehr, sehr schwierig wäre, die Felder korrekt zu extrahieren.Erläuterung : Nach dem
shift
soll die Variable b den Rest des zu übergebenden Materials enthalten, unabhängig von Leerzeichen oder Ähnlichem. Dies[ -n "$b" ] && echo $b
ist ein Schutz, so dass wir b nur drucken, wenn es einen Inhalt hat.quelle
"$*"
statt zu verwenden"$@"
. (3) Ich wollte Ihre Antwort positiv bewerten, habe es aber nicht getan, weil Sie "zweimal verschieben" sagen, aber Sie zeigen sie nicht wirklich im Code an. (4) Wenn Sie möchten, dass ein Skript einen Wert mit mehreren Wörtern von der Befehlszeile übernimmt, ist es wahrscheinlich besser, den Benutzer aufzufordern, den gesamten Wert in Anführungszeichen zu setzen. … (Fortsetzung)Philippines 6014
), führende Leerzeichen, nachfolgende Leerzeichen oder Tabulatoren zu verwenden. (5) Übrigens können Sie möglicherweise auch das tun, was Sie hier tun, wenn Sie mit Bash arbeitenx="${*:3}"
.shift
Befehl zusammenhängt. Sie beziehen sich vielleicht auf subtile Unterschiede zwischen $ @ und $ *. Es bleibt jedoch die Tatsache bestehen, dass mein Snippet oben die Position genau extrahieren kann, unabhängig davon, wie viele Leerzeichen sie hat, entweder am Ende oder vorne, es spielt keine Rolle. Nach der Schicht enthält der Standort den korrekten Standort.shift
Behandeln Sie Befehlszeilenargumente wie eine FIFO-Warteschlange. Bei jedem Aufruf wird ein Element nach links verschoben.quelle