Tại sao tôi cần sử dụng đĩa CD $ @ @ thay vì đĩa cd $ 1 USD khi viết trình bao bọc cho cd?


25

Ở những nơi khác tôi đã thấy một chức năng cd như dưới đây:

cd()
{
 builtin cd "$@"
}

Tại sao nên sử dụng $@thay vì $1?

Tôi đã tạo một thư mục thử nghiệm "r st" và gọi tập lệnh chứa hàm này và nó hoạt động theo cách nào đó

$ . cdtest.sh "r st"

nhưng $ . cdtest.sh r stthất bại cho dù tôi đã sử dụng "$@"hay"$1"


1
cd "$*"cũng sẽ không hoạt động chính xác với hơn 1 arg.
GoFundMonica - codidact.org

Câu trả lời:


57

Bởi vì, theo bash(1), cdlấy lý lẽ

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

do đó, thư mục thực sự có thể không ở trong $1đó thay vào đó có thể là một tùy chọn như -Lhoặc một cờ khác.

Làm thế nào là xấu này?

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

Những điều có thể đi rất xiên nếu bạn kết thúc không phải là nơi bạn mong đợi sử dụng cd "$1"...


19

Sử dụng "$@"sẽ chuyển tất cả các đối số đến cdnơi như $1sẽ chỉ vượt qua đối số đầu tiên.

Trong ví dụ của bạn

$ . cdtest.sh "r st"

luôn luôn hoạt động khi bạn chỉ vượt qua trong một đối số, nhưng nếu bạn đã vượt qua trong một cờ cũng như

$ . cdtest.sh -L "r st"

Sau đó, "$@"sẽ chỉ thực hiện chính xác nơi "$1"sẽ mở rộng để cd -Lmất hoàn toàn thư mục.

Tuy nhiên

$ . cdtest.sh r st

Thất bại trong cả hai trường hợp khi bạn chuyển hai tham số cho cd rstđó không phải là cách hợp lệ để thực thi cd. Các tham số được phân tách bằng khoảng trắng phải được trích dẫn (như trong ví dụ đầu tiên của bạn) hoặc esc thoát ( r\ st) để được coi là một đối số.

Tuy nhiên, trong trường hợp của cd, việc truyền cờ và bạn không thể vượt qua trong nhiều thư mục là điều không phổ biến, do đó bạn sẽ không thấy sự khác biệt trong việc sử dụng trong thế giới thực của một trong hai "$1"hoặc "$@"cho cd. Nhưng đối với các lệnh khác, bạn sẽ nhận thấy một sự khác biệt vì vậy tốt nhất là luôn luôn sử dụng "$@"khi bạn muốn tạo một hàm bao bọc hoặc tập lệnh như thế này.


14

Cũng có trường hợp khi không có đối số:

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

cdkhông có bất kỳ đối số thay đổi vào thư mục nhà. Không có bất kỳ đối số nào, "$@"mở rộng thành không có gì, nhưng "$1"mở rộng thành chuỗi rỗng. Đây là khác nhau:

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

Hơi không liên quan, nhưng: Cuối cùng tôi cũng hiểu tại sao một đối số null cdlà một điều tốt. Nó gây ra lỗi thay vì thay đổi thư mục chính. Với một số lệnh khác, đáng chú ý rsync, một đối số đầu tiên null gây ra hành vi không mong muốn (bao gồm thư mục hiện tại trong các nguồn chuyển).
Joe

4

Các đối số cho một tập lệnh bash được phân cách bằng dấu cách. $ 1 là đối số đầu tiên. Trong ví dụ của bạn ...

Trong ví dụ 1, $ 1 là chuỗi "r st" ... trong ví dụ thứ hai, $ 1 là chuỗi một ký tự 'r' ...

$ @ là tất cả các đối số.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.