Mengapa saya harus menggunakan cd "$ @" alih-alih cd "$ 1" saat menulis pembungkus untuk cd?

25

Di tempat lain saya telah melihat fungsi cd seperti di bawah ini:

cd()
{
 builtin cd "$@"
}

mengapa disarankan untuk menggunakan $@bukan $1?

Saya membuat direktori uji "rst" dan memanggil skrip yang berisi fungsi ini dan itu berhasil baik

$ . cdtest.sh "r st"

tetapi $ . cdtest.sh r stgagal apakah saya menggunakan "$@"atau"$1"

Ravi Kumar
sumber
1
cd "$*"juga tidak akan bekerja dengan benar dengan lebih dari 1 arg.
GoFundMonica - codidact.org

Jawaban:

57

Karena, menurut bash(1), cdbutuh argumen

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

jadi karena itu direktori sebenarnya mungkin tidak berada di dalam $1yang bisa menjadi pilihan seperti -Latau bendera lain.

Seberapa buruk ini?

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

Hal-hal bisa menjadi sangat serba salah jika Anda tidak berada di tempat yang Anda harapkan menggunakan cd "$1"...

thrig
sumber
19

Menggunakan "$@"akan meneruskan semua argumen ke cdtempat yang $1hanya akan melewati argumen pertama.

Dalam contoh Anda

$ . cdtest.sh "r st"

selalu berfungsi karena Anda hanya melewati satu argumen, tetapi jika Anda harus memberikan sebuah flag juga

$ . cdtest.sh -L "r st"

Maka hanya "$@"akan mengeksekusi dengan benar di mana "$1"akan berkembang menjadi cd -Lkehilangan direktori sepenuhnya.

Namun

$ . cdtest.sh r st

Gagal dalam kedua kasus saat Anda mengirimkan dua parameter ke cd, rdan styang bukan cara yang valid untuk mengeksekusi cd. Parameter dipisahkan oleh spasi yang harus dikutip (seperti dalam contoh pertama Anda) atau melarikan diri ( r\ st) untuk diperlakukan sebagai satu argumen.

Dalam kasus cd namun sangat jarang untuk lulus dalam bendera dan Anda tidak bisa lewat di beberapa direktori sehingga Anda tidak akan melihat perbedaan dalam penggunaan dunia nyata baik "$1"atau "$@"untuk cd. Tetapi untuk perintah lain, Anda akan melihat perbedaan sehingga praktik terbaik adalah selalu menggunakan "$@"ketika Anda ingin membuat fungsi pembungkus atau skrip seperti ini.

Michael Daffin
sumber
14

Ada juga kasus ketika tidak ada argumen:

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

cdtanpa perubahan argumen ke direktori home. Tanpa argumen apa pun, "$@"ekspansi menjadi kosong, tetapi "$1"ekspansi ke string kosong. Ini berbeda:

$ args() { for i in "$@"; do echo "|$i|"; done; }
$ args
$ args ""
||
muru
sumber
Agak tidak berhubungan, tetapi: Saya akhirnya mengerti mengapa argumen nol cdadalah hal yang baik. Ini menyebabkan kesalahan alih-alih mengubah ke direktori home. Dengan beberapa perintah lain, terutama rsync, argumen nol pertama menyebabkan perilaku yang tidak terduga (termasuk direktori saat ini di sumber transfer).
Joe
4

Argumen untuk skrip bash dibatasi oleh ruang. $ 1 adalah argumen pertama. Dalam contoh Anda ...

Dalam contoh 1, $ 1 adalah string "r st" ... dalam contoh kedua, $ 1 adalah string satu karakter 'r' ...

$ @ adalah semua argumen.

Cap
sumber