Làm cách nào để sử dụng $ * trong khi bỏ qua các biến đầu vào nhất định như $ 1 và $ 2 trong tập lệnh bash?


15

Ví dụ,

elif [[ $append = $1 ]]
then
  touch ~/directory/"$2".txt
  echo "$variable_in_question" >> ~/directory/"$2".txt

để tạo một tệp văn bản chứa tất cả các đầu vào sau "$2"hoặc nối thêm một tệp văn bản hiện có với tất cả các đầu vào sau "$2", tôi sẽ sử dụng cái gì thay cho "$variable_in_question"dòng 4?

Tôi về cơ bản muốn "$*", nhưng bỏ qua "$1""$2".

Câu trả lời:


32

Bạn có thể sử dụng bashMở rộng tham số để chỉ định một phạm vi, điều này cũng hoạt động với các tham số vị trí. Đối với $3... $nnó sẽ là:

"${@:3}" # expands to "$3" "$4" "$5" …
"${*:3}" # expands to "$3 $4 $5 …"

Hãy nhận ra rằng cả hai $@$*bỏ qua các đối số đầu tiên $0. Nếu bạn tự hỏi nên sử dụng cái nào trong trường hợp của bạn: rất có thể bạn muốn trích dẫn $@. Không sử dụng $*trừ khi bạn rõ ràng không muốn các đối số được trích dẫn riêng lẻ.

Bạn có thể dùng thử như sau:

$ bash -c 'echo "${@:3}"' 0 1 2 3 4 5 6
3 4 5 6
$ echo 'echo "${@:3}"' >script_file
$ bash script_file 0 1 2 3 4 5 6
2 3 4 5 6

Lưu ý rằng trong ví dụ đầu tiên $0được điền với đối số đầu tiên 0trong khi khi được sử dụng trong tập lệnh $0thay vào đó chứa đầy tên của tập lệnh, như ví dụ thứ hai hiển thị. Tên của kịch bản bashtất nhiên đối số đầu tiên, chỉ là thông thường nó không được nhận thức như vậy - điều tương tự cũng xảy ra đối với một kịch bản được thực thi và được gọi là trực tiếp. Vì vậy, trong ví dụ đầu tiên, chúng ta có $0= 0, $1= 1vv trong khi trong lần thứ hai, nó $0= script_file, $1= 0, $2= 1vv.; ${@:3}chọn mọi đối số bắt đầu bằng $3.

Một số ví dụ bổ sung cho các phạm vi có thể:

 # two arguments starting with the third
$ bash -c 'echo "${@:3:2}"' 0 1 2 3 4 5 6
3 4
 # every argument starting with the second to last one
 # a negative value needs either a preceding space or parentheses
$ bash -c 'echo "${@: -2}"' 0 1 2 3 4 5 6
5 6
 # two arguments starting with the fifth to last one
$ bash -c 'echo "${@:(-5):2}"' 0 1 2 3 4 5 6
2 3

Đọc thêm:


27

Bạn có thể sử dụng shiftnội dung:

$ help shift
shift: shift [n]
    Shift positional parameters.

    Rename the positional parameters $N+1,$N+2 ... to $1,$2 ...  If N is
    not given, it is assumed to be 1.

    Exit Status:
    Returns success unless N is negative or greater than $#.

Ví dụ. được

$ cat argtest.bash 
#!/bin/bash

shift 2

echo "$*"

sau đó

$ ./argtest.bash foo bar baz bam boo
baz bam boo

3
@Oreoplasm Tôi nghĩ rằng điều đáng nói là shiftcách tiếp cận này sẽ khiến bạn không thể truy cập $1$2sau khi bạn chuyển chúng. Trong tập lệnh của bạn, bạn sử dụng $2cùng với $variable_in_question, bạn cần thay đổi điều đó hoặc sử dụng phương pháp Mở rộng tham số.
tráng miệng ngày

6
shiftlà tốt khi là người đầu tiên trở lên args là đặc biệt và nó làm cho tinh thần để đón chúng ra thành các biến riêng biệt ( foo="$1"; bar="$2";hoặc if [[ something with $1 ]];then blah blah; shift. Nhưng @ câu trả lời món tráng miệng với cách tiếp cận không phá hủy là tốt đẹp trong các trường hợp khác khi bạn làm vẫn muốn danh sách đầy đủ sau hoặc khi bạn sử dụng cú pháp fancier để chọn ra một phạm vi giới hạn của các đối số, không ở ngoài vô cực, mà không đưa ra các đối số trống cho một lệnh nếu $@không có nhiều phần tử đó.
Peter Cordes

13

Nói chung, bạn có thể sao chép các tham số vị trí vào một mảng, xóa các chỉ mục tùy ý của mảng và sau đó sử dụng mảng để mở rộng để chính xác các chỉ số bạn muốn mà không làm mất các đối số ban đầu của bạn.

Ví dụ: nếu tôi muốn tất cả các đối số ngoại trừ thứ nhất, thứ tư và thứ năm:

args=( "$@" )
unset args[0] args[3] args[4]
echo "${args[@]}"

Trong bản sao, các chỉ số được thay đổi bởi 1, vì $0không phải là một phần của $@.


1
Tất nhiên, có thể kết hợp điều đó, ví dụ echo "${args[@]:2}"cho đối số thứ ba đến cuối cùng.
tráng miệng
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.