$#
là số lượng đối số, nhưng hãy nhớ nó sẽ khác nhau trong một hàm.
$#
là số lượng tham số vị trí được truyền cho hàm script, shell hoặc shell . Điều này là do, trong khi một hàm shell đang chạy, các tham số vị trí tạm thời được thay thế bằng các đối số cho hàm . Điều này cho phép các hàm chấp nhận và sử dụng các tham số vị trí riêng của chúng.
Tập lệnh này luôn in 3
, bất kể có bao nhiêu đối số được truyền cho chính tập lệnh, bởi vì "$#"
trong hàm f
mở rộng đến số lượng đối số được truyền cho hàm:
#!/bin/sh
f() {
echo "$#"
}
f a b c
Điều này rất quan trọng vì nó có nghĩa là mã như thế này không hoạt động như bạn mong đợi, nếu bạn không quen với cách các tham số vị trí hoạt động trong các hàm shell:
#!/bin/sh
check_args() { # doesn't work!
if [ "$#" -ne 2 ]; then
printf '%s: error: need 2 arguments, got %d\n' "$0" "$#" >&2
exit 1
fi
}
# Maybe check some other things...
check_args
# Do other stuff...
Trong check_args
, $#
mở rộng đến số lượng đối số được truyền cho chính hàm, mà trong tập lệnh đó luôn là 0.
Nếu bạn muốn chức năng như vậy trong một hàm shell, thay vào đó bạn phải viết một cái gì đó như thế này:
#!/bin/sh
check_args() { # works -- the caller must pass the number of arguments received
if [ "$1" -ne 2 ]; then
printf '%s: error: need 2 arguments, got %d\n' "$0" "$1" >&2
exit 1
fi
}
# Maybe check some other things...
check_args "$#"
Điều này hoạt động vì $#
được mở rộng bên ngoài hàm và được truyền cho hàm như một trong các tham số vị trí của nó . Bên trong hàm, $1
mở rộng thành tham số vị trí đầu tiên được truyền cho hàm shell, thay vì cho tập lệnh mà nó là một phần của.
Như vậy, giống như $#
, các thông số đặc biệt $1
, $2
vv, cũng như $@
và $*
, cũng liên quan đến các đối số truyền cho một chức năng, khi họ được mở rộng trong hàm. Tuy nhiên, $0
không không thay đổi tên của hàm, đó là lý do tôi vẫn còn có thể sử dụng nó để tạo ra một thông báo lỗi chất lượng.
$ ./check-args-demo a b c
./check-args-demo: error: need 2 arguments, got 3
Tương tự, nếu bạn xác định một hàm bên trong hàm khác, bạn đang làm việc với các tham số vị trí được truyền cho hàm trong cùng, trong đó việc mở rộng được thực hiện:
#!/bin/sh
outer() {
inner() {
printf 'inner() got %d arguments\n' "$#"
}
printf 'outer() got %d arguments\n' "$#"
inner x y z
}
printf 'script got %d arguments\n' "$#"
outer p q
Tôi đã gọi kịch bản này nested
và (sau khi chạy chmod +x nested
) tôi đã chạy nó:
$ ./nested a
script got 1 arguments
outer() got 2 arguments
inner() got 3 arguments
Vâng tôi biết. "1 đối số" là một lỗi số nhiều.
Các tham số vị trí cũng có thể được thay đổi.
Nếu bạn đang viết một tập lệnh, các tham số vị trí bên ngoài hàm sẽ là các đối số dòng lệnh được truyền cho tập lệnh trừ khi bạn đã thay đổi chúng .
Một cách phổ biến để thay đổi chúng là với shift
nội trang, dịch chuyển từng tham số vị trí sang trái, bỏ cái đầu tiên và giảm $#
1:
#!/bin/sh
while [ "$#" -ne 0 ]; do
printf '%d argument(s) remaining.\nGot "%s".\n\n' "$#" "$1"
shift
done
$ ./do-shift foo bar baz # I named the script do-shift.
3 argument(s) remaining.
Got "foo".
2 argument(s) remaining.
Got "bar".
1 argument(s) remaining.
Got "baz".
Chúng cũng có thể được thay đổi với set
nội dung:
#!/bin/sh
printf '%d args: %s\n' "$#" "$*"
set foo bar baz
printf '%d args: %s\n' "$#" "$*"
$ ./set-args a b c d e # I named the script set-args.
5 args: a b c d e
3 args: foo bar baz
$#
? Bạn muốn đạt được những gì? Nơi mà bạn đã nhận được lệnh này. Nó không liên quan gì cả.