Ich habe gerade zufällig herausgefunden, dass wir in Bash einen Befehl einer Variablen zuweisen können, ohne zu verwenden alias
.
g=date
$g
Mon Jun 27 13:00:40 MYT 2016
Das funktioniert. Hier ist ein weiteres Beispiel:
jj="ping yahoo.com"
$jj
PING yahoo.com (98.138.253.109) 56(84) bytes of data.
64 bytes from ir1.fp.vip.ne1.yahoo.com (98.138.253.109): icmp_seq=1 ttl=41 time=347 ms
64 bytes from ir1.fp.vip.ne1.yahoo.com (98.138.253.109): icmp_seq=2 ttl=41 time=345 ms
64 bytes from ir1.fp.vip.ne1.yahoo.com (98.138.253.109): icmp_seq=3 ttl=41 time=345 ms
Ich verwende diese Version von Bashbash --version GNU bash, version 4.1.2(1)-release (x86_64-redhat-linux-gnu)
Ich habe nachgesehenStapelaustauschUndtldp abs, aber ich habe nicht herausgefunden, dass wir es so machen können. Ist das also eine neue Funktion von Bash oder etwas, das übersehen wird? Wird das berücksichtigt?Befehlsersetzung?
Antwort1
Bei interaktiver Nutzung liest die Shell Eingabezeilen vom Endgerät. Nach der Eingabe einer Zeile wird dieseanalysiertdurch Aufspaltung inToken(Wörter und Operatoren). Die Token oder Wörter werden dann in einer bestimmten Reihenfolge erweitert oder aufgelöst.
Hinweis: Im Allgemeinen ist es besser, auf die kanonische Informationsquelle wie Projektdokumentation oder Branchenspezifikationen zurückzugreifen als auf Quellen aus zweiter Hand wie den Advanced Bash-Scripting Guide, Online-Tutorials, Bücher – oder sogar Stack Exchange :). Solche Quellen aus zweiter Hand sind nützlich, um Konzepte in einfacherer Sprache einzuführen und zu erklären, aber sie sind normalerweise nicht als vollständig oder als Ersatz für die offizielle Dokumentation gedacht. Die Informationen in Quellen aus zweiter Hand können auch veraltet sein.
In diesem FallPOSIX-Spezifikation zum Parsen einfacher Befehlebesagt, dass
- Die Wörter, die keine Variablenzuweisungen oder Umleitungen sind, müssen erweitert werden. Wenn nach ihrer Erweiterung noch Felder übrig bleiben, wird das erste Feld als Befehlsname betrachtet und die restlichen Felder sind die Argumente für den Befehl.
DerAbschnitt des Bash-Handbuchs zur einfachen Befehlserweiterungstellt auch fest, dass
- Die Wörter, die keine Variablenzuweisungen oder Umleitungen sind, werden erweitert (siehe Shell-Erweiterungen). Wenn nach der Erweiterung noch Wörter übrig sind, wird das erste Wort als Name des Befehls betrachtet und die restlichen Wörter sind die Argumente.
Antwort2
Dies ist keine Befehlssubstitution, es istVariableSubstitution. Sie weisen einer Variablen keinen Befehl zu, sondern eine Zeichenfolge. Der Befehl wird ausgeführt, wenn Sie die Variable verwenden, nicht zum Zeitpunkt der Zuweisung.
g=date
speichert den String date
in der Variable g
. Wenn Sie dann ausführen echo "$g"
, wird der Wert von ausgegeben g
, d. h. date
(gefolgt von einem Zeilenumbruch), da der Wert von als erstes Argument g
an den Befehl übergeben wird . Wenn Sie ausführen , wird der String an die erste Stelle des Befehls gesetzt , es handelt sich also um den Befehlsnamen.echo
"$g"
date
Bei $jj
kommt ein zweiter Faktor ins Spiel. Da die Variablenerweiterung außerhalb der Anführungszeichen steht,„Split+Glob-Operator“wird auf den Wert angewendet. In diesem Fall bedeutet dies, dass der Wert jj
in zwei durch Leerzeichen getrennte Wörter aufgeteilt wird. Somit ping
landet das Wort an der Befehlsposition und das Wort yahoo.com
ist das erste Argument.
Antwort3
Dies ist das erwartete Verhalten und funktioniert schon seit Ewigkeiten. Es ist nützlich zum Erstellen von Befehlen in Skripten.
Nehmen wir zum Beispiel an, dass ich manchmal eine Dekomprimierung auf eine Eingabe anwenden sollte, bevor ich sie in eine Pipeline sende (und danach eine Komprimierung auf die Ausgabe), manchmal aber nicht. Verwenden Sie dazu bash
:
if (( use_compression == 1 )); then
infilter='gzip -d -c'
outfilter='gzip -c'
else
infilter='cat'
outfilter='cat'
fi
$infilter "$indatafile" | somepipeline | $outfilter >"$outdatafile"
Handelt es sich um eine Befehlssubstitution? Nein. „Befehlssubstitution“ bezieht sich speziell auf das Ersetzen $(...)
oder die Backtick-Variante durch den Inhalt ihrer Ausgabe.
Dies ist stattdessenParametererweiterung, d. h. das einfache Ersetzen der Parameter durch ihre Werte. Dies geschieht, bevor der Befehl tatsächlich ausgeführt wird, weshalb es funktioniert.
Dies bedeutet, dass Dinge wie das Folgende auch auf der Kommandozeile funktionieren:
$ decompress='gzip -d -c'
$ ${decompress/g/gun/} filename >unzippedfilename
(das würde ausführen gunzip
statt gzip
)
BEARBEITEN:Über Aliase.
Im bash
Handbuch steht:
Für fast alle Zwecke werden Aliase durch Shell-Funktionen ersetzt.
... und ich stimme zu.
Aliase eignen sich für kurze Dinge wie
alias ls="ls -F"
(das ist der einzige Alias, den ich in meinen eigenen Shell-Sitzungen habe)
Sie möchten wahrscheinlich keine Parametererweiterungen für „Aliasing“-Befehle in der Befehlszeile verwenden. Wenn nicht aus einem anderen Grund, dann ist das Eintippen ein echter Krampf. Die Parametererweiterung ermöglicht außerdem keine Ausführung etwas komplexerer Aufgaben wie Pipelining.
Wenn Sie regelmäßig mäßig komplexe Vorgänge ausführen, verwenden Sie hierfür stattdessen Shell-Funktionen.
Nehmen wir das Beispiel aus der akzeptierten Antwort aufdie U&L-Frage(auf das Sie in den Kommentaren unten verlinken):
alias my_File='ls -f | grep -v /'
Dieser Alias funktioniert offensichtlich, aber die Verwendung
my_File='ls -f | grep -v /'
funktioniert nicht, wenn Sie dann versuchen, es $my_File
als Befehl in der Befehlszeile zu verwenden (wie in diesem U&L-Thread erklärt).
Mit einer Shell-Funktion können Sie beispielsweise auch Argumente übergeben:
function my_File {
ls -l "$@" | fgrep -v '/'
}
$ my_File -iF symlink
84416642 lrwxr-xr-x 1 kk staff 4 Jun 27 09:03 symlink@ -> file
Antwort4
Es handelt sich dabei lediglich um die Verwendung von Shell-Variablen, einem Konzept, das seit Jahrzehnten existiert und (ohne Übertreibung) so funktioniert.
Wenn Sie eine Variable in eine Befehlszeile einfügen, ersetzt die Shell diese und führt dann den Befehl aus. Wenn Ihre Variable also am Anfang steht, wird sie offensichtlich als Befehl betrachtet.