Dlaczego muszę używać cd „$ @” zamiast cd „$ 1” podczas pisania opakowania na cd?


25

Gdzie indziej widziałem funkcję cd, jak poniżej:

cd()
{
 builtin cd "$@"
}

dlaczego zaleca się używać $@zamiast $1?

Utworzyłem katalog testowy „r st” i wywołałem skrypt zawierający tę funkcję i działał on w obie strony

$ . cdtest.sh "r st"

ale $ . cdtest.sh r stzawiodło, czy użyłem "$@"czy"$1"


1
cd "$*"również nie będzie działać poprawnie z więcej niż 1 arg.
GoFundMonica - codidact.org

Odpowiedzi:


57

Ponieważ, zgodnie z bash(1), cdbierze argumenty

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

dlatego katalog może nie być w rzeczywistości, $1ponieważ może to być opcja taka jak -Llub inna flaga.

Jak źle to jest?

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

Wszystko może pójść nie tak, jeśli nie skończysz w miejscu, w którym spodziewasz się cd "$1"


19

Użycie "$@"spowoduje przekazanie wszystkich argumentów do miejsca, cdgdzie $1zostanie przekazany tylko pierwszy argument.

W twoich przykładach

$ . cdtest.sh "r st"

zawsze działa, gdy przekazujesz tylko jeden argument, ale jeśli miałbyś również przekazać flagę, taką jak

$ . cdtest.sh -L "r st"

Wtedy tylko "$@"wykona się poprawnie, gdzie "$1"rozwinie się do cd -Lutraty katalogu całkowicie.

jednak

$ . cdtest.sh r st

Nie powiedzie się w obu przypadkach, jak przechodzą dwa parametry na CD, ri stktóry nie jest prawidłowym sposobem wykonać cd. Parametry są oddzielone spacjami, które muszą być cytowane (jak w twoim pierwszym przykładzie) lub escaped ( r\ st), aby traktować je jako jeden argument.

Jednak w przypadku cd przekazywanie flag jest bardzo rzadkie i nie można przekazywać wielu katalogów, więc nie zobaczysz różnicy w korzystaniu z jednego "$1"lub "$@"drugiego z nich w świecie rzeczywistym . Ale dla innych poleceń, będzie zauważyć różnicę więc najlepiej jest, aby zawsze używać "$@", gdy chcemy utworzyć funkcję otoki lub skryptu takiego.


14

Jest również przypadek, gdy nie ma argumentów:

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

cdbez żadnych argumentów zmiany w katalogu domowym. Bez żadnych argumentów "$@"rozwija się do zera, ale "$1"rozwija się do pustego łańcucha. Są różne:

$ args() { for i in "$@"; do echo "|$i|"; done; }
$ args
$ args ""
||

Nieco niepowiązane, ale: W końcu rozumiem, dlaczego zerowy argument cdjest dobrą rzeczą. Powoduje błąd zamiast przejścia do katalogu domowego. W przypadku niektórych innych poleceń, w szczególności rsyncpierwszy zerowy argument powoduje nieoczekiwane zachowanie (obejmuje bieżący katalog w źródłach przesyłania).
Joe

4

Argumenty do skryptu bash są rozdzielane spacjami. 1 $ to pierwszy argument. W twoich przykładach ...

W przykładzie 1 $ 1 to ciąg „r st” ... w drugim przykładzie $ 1 to ciąg jednego znaku „r” ...

$ @ to wszystkie argumenty.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.