Warum muss ich CD "$ @" anstelle von CD "$ 1" verwenden, wenn ich einen Wrapper für CD schreibe?

25

An anderer Stelle habe ich eine CD gesehen, die wie folgt funktioniert:

cd()
{
 builtin cd "$@"
}

warum wird es empfohlen, $@anstatt zu verwenden $1?

Ich habe ein Testverzeichnis "r st" erstellt und das Skript aufgerufen, das diese Funktion enthält, und es hat so oder so funktioniert

$ . cdtest.sh "r st"

aber $ . cdtest.sh r stscheiterte, ob ich verwendet "$@"oder"$1"

Ravi Kumar
quelle
1
cd "$*"funktioniert auch nicht mit mehr als 1 arg.
GoFundMonica - codidact.org

Antworten:

57

Denn nach bash(1), cdnimmt Argumente

   cd [-L|[-P [-e]] [-@]] [dir]
          Change  the  current  directory to dir.  if dir is not supplied,
          ...

Das Verzeichnis befindet sich also möglicherweise nicht in $1diesem Verzeichnis, da dies stattdessen eine Option wie -Loder ein anderes Flag sein kann.

Wie schlimm ist das

$ cd -L /var/tmp
$ pwd
/var/tmp
$ cd() { builtin cd "$1"; }
$ cd -L /var/tmp
$ pwd
/home/jhqdoe
$ 

Es könnte sehr schief gehen, wenn Sie nicht dort landen, wo Sie es erwarten cd "$1"...

Thrig
quelle
19

Bei Verwendung von "$@"werden alle Argumente an übergeben, cdwobei as $1nur das erste Argument übergibt.

In deinen Beispielen

$ . cdtest.sh "r st"

funktioniert immer, wenn Sie nur ein Argument übergeben, aber wenn Sie auch ein Flag übergeben, wie z

$ . cdtest.sh -L "r st"

Dann wird nur "$@"richtig ausgeführt, wo "$1"es zu einem cd -Lvollständigen Verlust des Verzeichnisses kommt.

jedoch

$ . cdtest.sh r st

Schlägt fehl , in beiden Fällen , wie Sie mit zwei Parametern auf CD, rund stdas ist keine gültige Weise cd auszuführen. Parameter werden durch Leerzeichen getrennt, die in Anführungszeichen (wie im ersten Beispiel) oder mit Escapezeichen ( r\ st) gesetzt werden müssen, um als ein Argument behandelt zu werden.

Im Falle von CD ist es jedoch sehr ungewöhnlich, Flags zu übergeben, und Sie können nicht mehrere Verzeichnisse übergeben, so dass Sie den Unterschied in einer realen Verwendung von CD "$1"oder "$@"CD nicht bemerken. Bei anderen Befehlen werden Sie jedoch einen Unterschied feststellen. Daher empfiehlt es sich, immer zu verwenden, "$@"wenn Sie eine Wrapper-Funktion oder ein Skript wie dieses erstellen möchten.

Michael Daffin
quelle
14

Es gibt auch den Fall, wenn es keine Argumente gibt:

$ cd /tmp; cd; pwd
/home/muru
$ cd_func() { builtin cd "$1"; }
$ cd_func /tmp; cd_func; pwd
/tmp

cdOhne Argumente wird das Ausgangsverzeichnis geändert. Wird ohne Argumente "$@"zu nichts "$1"erweitert , jedoch zu der leeren Zeichenfolge. Diese sind unterschiedlich:

$ args() { for i in "$@"; do echo "|$i|"; done; }
$ args
$ args ""
||
muru
quelle
Etwas verwandt, aber: Ich verstehe endlich, warum ein Nullargument für cdeine gute Sache ist. Es wird ein Fehler verursacht, anstatt in das Basisverzeichnis zu wechseln. Insbesondere bei einigen anderen Befehlen führt rsyncein Null-Argument zu unerwartetem Verhalten (enthält das aktuelle Verzeichnis in den Quellen der Übertragung).
Joe
4

Argumente für ein Bash-Skript sind durch Leerzeichen getrennt. $ 1 ist das erste Argument. In Ihren Beispielen ...

In Beispiel 1 ist $ 1 die Zeichenfolge "r st" ... im zweiten Beispiel ist $ 1 die Zeichenfolge "r" ...

$ @ sind alle Argumente.

RubberStamp
quelle