Bagaimana saya menggunakan $ * sambil menghilangkan variabel input tertentu seperti $ 1 dan $ 2 dalam skrip bash?

15

Sebagai contoh,

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

baik untuk membuat file teks yang berisi semua input berikut "$2", atau menambahkan file teks yang ada dengan semua input berikut "$2", apa yang akan saya gunakan sebagai pengganti "$variable_in_question"in line 4?

Saya pada dasarnya ingin "$*", tetapi menghilangkan "$1"dan "$2".

Oreoplasma
sumber

Jawaban:

32

Anda dapat menggunakan bashEkspansi Parameter untuk menentukan rentang, ini berfungsi dengan parameter posisi juga. Untuk $3... $nitu akan menjadi:

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

Sadarilah bahwa keduanya $@dan $*abaikan argumen pertama $0. Jika Anda bertanya-tanya mana yang akan digunakan dalam kasus Anda: sangat mungkin Anda ingin mengutip $@. Jangan gunakan $*kecuali Anda secara eksplisit tidak ingin argumen dikutip secara individual.

Anda dapat mencobanya sebagai berikut:

$ 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

Perhatikan bahwa dalam contoh pertama $0diisi dengan argumen pertama 0sementara ketika digunakan dalam skrip $0diisi dengan nama skrip, seperti yang ditunjukkan contoh kedua. bashTentu saja nama skrip adalah argumen pertama, hanya saja itu biasanya tidak dianggap seperti itu - hal yang sama berlaku untuk skrip yang dapat dieksekusi dan disebut "langsung". Jadi pada contoh pertama kita memiliki $0= 0, $1= 1dll. Sedangkan pada contoh kedua adalah $0= script_file, $1= 0, $2= 1dll .; ${@:3}memilih setiap argumen yang dimulai dengan $3.

Beberapa contoh tambahan untuk rentang yang memungkinkan:

 # 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

Bacaan lebih lanjut:

pencuci mulut
sumber
27

Anda dapat menggunakan shiftbuiltin:

$ 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 $#.

Ex. diberikan

$ cat argtest.bash 
#!/bin/bash

shift 2

echo "$*"

kemudian

$ ./argtest.bash foo bar baz bam boo
baz bam boo
Steeldriver
sumber
3
@Oreoplasma Saya pikir perlu disebutkan bahwa shiftpendekatannya akan membuat tidak mungkin untuk mengakses $1dan $2setelah Anda menggesernya. Dalam skrip yang Anda gunakan di $2samping $variable_in_question, Anda harus mengubahnya atau menggunakan pendekatan Ekspansi Parameter.
hidangan penutup
6
shiftbaik ketika yang pertama atau lebih args khusus dan masuk akal untuk memilih mereka ke dalam variabel yang terpisah ( foo="$1"; bar="$2";atau if [[ something with $1 ]];then blah blah; shift. Tapi jawaban @ makanan penutup dengan pendekatan non-destruktif menyenangkan dalam kasus lain ketika Anda lakukan masih ingin daftar lengkap kemudian , atau ketika Anda menggunakan sintaks yang lebih bagus untuk memilih rentang args yang terbatas, tidak hingga infinity, tanpa memperkenalkan argumen kosong pada perintah jika $@tidak memiliki banyak elemen
Peter Cordes
13

Secara umum, Anda dapat menyalin parameter posisi ke array, menghapus indeks array sewenang-wenang dan kemudian menggunakan array untuk memperluas ke indeks yang Anda inginkan, tanpa kehilangan argumen asli Anda.

Sebagai contoh, jika saya menginginkan semua argumen kecuali yang pertama, keempat dan kelima:

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

Dalam salinan, indeks digeser oleh 1, karena $0bukan bagian dari $@.

muru
sumber
1
Tentu saja mungkin untuk menggabungkannya, misalnya echo "${args[@]:2}"untuk argumen ketiga hingga terakhir.
hidangan penutup