Tập lệnh Bash để nhận và duyệt lại các tham số được trích dẫn


98

Tôi đang cố gắng nhận các tham số được trích dẫn của một tập lệnh bash để được một tập lệnh lồng nhau nhận một cách an toàn. Bất kỳ ý tưởng?

test.sh

#!/bin/bash
echo $*
bash myecho.sh $*

myecho.sh

#!/bin/bash
 echo $1
 echo $2
 echo $3
 echo $4

Mẫu vật:

bash test.sh aaa bbb '"ccc ddd"'

Kết quả:

aaa bbb "ccc ddd"
aaa
bbb
"ccc
ddd"

Kết quả mong muốn

aaa bbb "ccc ddd"
aaa
bbb
ccc ddd

2
Tôi vừa định hỏi câu hỏi đó! Thời gian tốt.
Scottie T

Câu trả lời:


70
#!/bin/bash
echo $*
bash myecho.sh "$@"

Lưu ý rằng cấu trúc "$ @" không phải là bash cụ thể và sẽ hoạt động với bất kỳ trình bao POSIX nào (ít nhất nó cũng có dấu gạch ngang). Cũng lưu ý rằng với đầu ra bạn muốn, bạn không cần thêm mức trích dẫn nào cả. IE chỉ cần gọi tập lệnh trên như:

./test.sh 1 2 "3 4"

5
"$ @" hoạt động với bất kỳ lớp vỏ Bourne hoặc phái sinh vỏ Bourne nào (từ năm 1978 trở đi), bao gồm cả Korn và Bash. Có lẽ 95% trường hợp sử dụng "$ @" là đúng và $ * là sai.
Jonathan Leffler

Đẹp! Nhưng, biết ai đó nếu có cách nào để lưu trữ nó "nguyên trạng" trong một biến không? Bản gốc $@không có sẵn bên trong một hàm (vì nó bị ghi đè bởi các đối số của hàm). Tôi cố gắng foovar="$@"foovar=$@+ "$foovar"trong chức năng và không ai làm việc: - /
bitifet

143

Bạn muốn sử dụng "$ @" (đô la được trích dẫn tại) để chuyển các tham số cho một chỉ số con. Như vậy ...

ls-color.sh:

#!/bin/bash
/bin/ls --color=auto "$@"    # passes though all CLI-args to 'ls'


Tại sao .....

Từ trang người đàn ông Bash :

$*- Mở rộng đến các tham số vị trí, bắt đầu từ một. Khi mở rộng xảy ra trong dấu ngoặc kép, nó sẽ mở rộng thành một từ duy nhất với giá trị của mỗi tham số được phân tách bằng ký tự đầu tiên của biến đặc biệt IFS. Nghĩa là, "$*"tương đương với "$1c$2c...", trong đó c là ký tự đầu tiên của giá trị của biến IFS. Nếu IFS không được đặt, các tham số được phân tách bằng dấu cách. Nếu IFS rỗng, các tham số được nối mà không có dấu phân tách can thiệp.

$@- Mở rộng đến các tham số vị trí, bắt đầu từ một. Khi mở rộng xảy ra trong dấu ngoặc kép, mỗi tham số sẽ mở rộng thành một từ riêng biệt. Nghĩa là, "$@"tương đương với "$1" "$2" ...Nếu phần mở rộng được trích dẫn kép xảy ra trong một từ, phần mở rộng của tham số đầu tiên được nối với phần đầu của từ gốc và phần mở rộng của tham số cuối cùng được nối với phần cuối cùng của từ gốc. từ ngữ. Khi không có tham số vị trí "$@"$@mở rộng thành không (nghĩa là chúng bị loại bỏ).


Thiết lập một số tập lệnh demo ...

echo 'echo -e "\$1=$1\n\$2=$2\n\$3=$3\n\$4=$4"' > echo-params.sh
echo './echo-params.sh $*' > dollar-star.sh
echo './echo-params.sh $@' > dollar-at.sh
echo './echo-params.sh "$*"' > quoted-dollar-star.sh
echo './echo-params.sh "$@"' > quoted-dollar-at.sh
chmod +x *.sh

"$@"- quote-dollar-at là một chuyển đổi danh tính để chuyển lại các args đến một vỏ con (~ 99% thời gian, đây là những gì bạn muốn làm):

./quoted-dollar-at.sh aaa '' "'cc cc'" '"ddd ddd"'
  # $1= aaa
  # $2=            
  # $3= 'cc cc'
  # $4= "ddd ddd"

"$*"- quote-dollar-star đập các args thành một chuỗi duy nhất (~ 1% thời gian bạn thực sự muốn hành vi này, ví dụ: trong điều kiện if [[ -z "$*" ]]; then ...:):

./quoted-dollar-star.sh aaa '' "'cc cc'" '"ddd ddd"'
  # $1= aaa  'cc cc' "ddd ddd"   
  # $2=                     
  # $3=             
  # $4=

$*/ $@- không có dấu ngoặc kép, cả hai dạng đều loại bỏ một cấp của dấu ngoặc kép và giải thích khoảng trắng từ các chuỗi bên dưới nhưng bỏ qua các ký tự trong dấu ngoặc kép (hầu như luôn luôn, đây là một sai lầm):

./dollar-star.sh aaa '' "'cc cc'" '"ddd ddd"'
  # $1= aaa
  # $2= 'cc                  
  # $3= cc'
  # $4= "ddd

./dollar-at.sh aaa '' "'cc cc'" '"ddd ddd"'
  # $1= aaa
  # $2= 'cc
  # $3= cc'
  # $4= "ddd

Nếu bạn muốn giải trí, bạn có thể sử dụng "$ @" để lồng mọi thứ sâu tùy thích, đẩy và đưa các phần tử ra khỏi ngăn xếp args nếu bạn muốn.

function identity() {
  "$@"
}
set -x
identity identity identity identity identity echo Hello \"World\"
# + identity identity identity identity identity echo Hello '"World"'
# + identity identity identity identity echo Hello '"World"'
# + identity identity identity echo Hello '"World"'
# + identity identity echo Hello '"World"'
# + identity echo Hello '"World"'
# + echo Hello '"World"'
# Hello "World"

1
Cảm ơn vì lời giải thích. Chỉ sử dụng "$ *" cho bí danh grep.
bóng tối

Bạn tiết kiệm ngày của tôi!
xyz
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.