Mengubah array menjadi argumen perintah?

40

Saya memiliki array "opsi" dari sebuah perintah.

my_array=(option1 option2 option3)

Saya ingin memanggil perintah ini dalam skrip bash, menggunakan nilai dari array sebagai opsi. Jadi, command $(some magic here with my_array) "$1"menjadi:

command -option1 -option2 -option3 "$1"

Bagaimana saya bisa melakukannya? Apa itu mungkin?

Seseorang masih menggunakan Anda MS-DOS
sumber
1
Jadi, Anda ingin menambahkan -awal setiap kata my_array?
Kevin
@ Kevin: Ya, dan jalankan. Semua baris di dalam skrip bash yang sama. Saya menanyakan hal ini karena opsi yang sama ini akan digunakan di banyak tempat di dalam skrip, jadi alih-alih menyalin semuanya, saya berpikir tentang sebuah array.
Seseorang masih menggunakan Anda MS-DOS
1
Ini mungkin tampak tidak ada gunanya, tetapi jika Anda membuat skrip shell besar mungkin Anda harus melihat perl, hal semacam ini sangat mudah dilakukan di sana.
alfa64

Jawaban:

43

Saya lebih suka bashcara yang sederhana :

command "${my_array[@]/#/-}" "$1"

Salah satu alasannya adalah spasi. Sebagai contoh jika Anda memiliki:

my_array=(option1 'option2 with space' option3)

The sedsolusi berbasis akan mengubahnya di -option1 -option2 -with -space -option3(panjang 5), tetapi di atas bashekspansi akan mengubahnya menjadi -option1 -option2 with space -option3(panjang masih 3). Jarang, tetapi terkadang ini penting, misalnya:

bash-4.2$ my_array=('Ffoo bar' 'vOFS=fiz baz')
bash-4.2$ echo 'one foo bar two foo bar three foo bar four' | awk "${my_array[@]/#/-}" '{print$2,$3}'
 two fiz baz three
manatwork
sumber
Jika saya mengerti dengan benar, substitusi variabel ini tidak dapat dimasukkan ke dalam fungsi, atau ditugaskan ke variabel, kan? Perlu masuk langsung ke permintaan perintah.
Konrad Rudolph
1
@KonradRudolph, Anda dapat menetapkan ke variabel lain selama Anda melakukannya sebagai array yang tugas: somevar=("${my_array[@]/#/-}")(Perhatikan tanda kurung di sekitar nilai.) Kemudian tentu saja Anda harus tetap menangani sebagai array yang ketika menggunakannya: echo "${somevar[@]}". Mengenai fungsi, di sana Anda terlalu dibatasi oleh kemungkinan bahasa. Anda dapat melewatkan sebuah array: somefunc "${my_array[@]/#/-}", kemudian di dalam Anda akan memilikinya di $@: function somefunc() { echo "$@"; }. Tetapi hal yang sama $@akan mengandung parameter lain juga, jika ada, dan tidak ada cara lain untuk mengembalikan array yang diubah daripada stdout.
manatwork
Cukup aneh, tidak berfungsi dengan zsh. Pertama kali saya menemukan sesuatu yang bekerja di bash tetapi tidak zsh.
Hi-Angel
@ Hai-Angel, apakah Anda yakin Anda menggunakan @subscript array? Saya memberikannya tes dengan zsh 5.5.1 dan satu-satunya perbedaan yang saya perhatikan adalah apa zsh hanya mengawali setiap item saat ditulis ${my_array[@]/#/-}, sementara bash melakukannya untuk *subskrip juga.
manatwork
Oh, maaf, saya mungkin telah mengacaukan sesuatu, memang bekerja untuk saya!
Hi-Angel
2

Saya tidak memproses bahwa itu dalam sebuah array dan berpikir dipisahkan oleh spasi. Solusi ini akan bekerja dengan itu, tetapi mengingat bahwa itu adalah array, ikuti solusi manatwork ( @{my_array[@]/#/-}).


Ini tidak terlalu buruk dengan seddan subkulit. Seberapa mudah regex tergantung pada apa yang dapat Anda jamin tentang opsi. Jika semua opsi adalah satu "kata" ( a-zA-Z0-9hanya), maka batas kata awal yang sederhana ( \<) akan cukup:

command $(echo $my_array | sed 's/\</-/g') "$1"

Jika opsi Anda memiliki karakter lain (kemungkinan besar -), Anda akan memerlukan sesuatu yang sedikit lebih rumit:

command $(echo $my_array | sed 's/\(^\|[ \t]\)\</\1-/g') "$1"

^cocok dengan awal baris, [ \t]cocok dengan spasi atau tab, \|cocok dengan kedua sisi ( ^atau [ \t]), \( \)kelompok (untuk \|) dan menyimpan hasilnya, \<cocok dengan awal kata. \1memulai penggantian dengan menjaga pertandingan pertama dari parens ( \(\)), dan -tentu saja menambahkan tanda hubung yang kita butuhkan.

Ini bekerja dengan gnu sed, jika mereka tidak bekerja dengan Anda, beri tahu saya.

Dan jika Anda akan menggunakan hal yang sama beberapa kali, Anda mungkin ingin menghitungnya sekali saja dan menyimpannya:

opts="$(echo $my_array | sed 's/\(^\|[ \t]\)\</\1-/g')"
...
command $opts "$1"
command $opts "$2"
Kevin
sumber
Ini tidak bekerja dengan Mac OS X sed, jadi saya perlu menggunakan gsed(saya menginstal menggunakan homebrew). Hal lain: alih-alih echo $my_array, saya perlu lakukan echo ${my_array[@]}untuk mendapatkan semua item dari my_array: echo $my_arrayhanya memberi saya elemen pertama. Tapi terima kasih atas jawaban dan penjelasan regex, khususnya tentang "batas kata", ini sangat berguna. :)
Seseorang masih menggunakan Anda MS-DOS
Saya ingin keluar dari skrip jika sistem sed tidak kompatibel dengan fitur batas kata ini. Bagaimana saya melakukannya? Mencetak versi sed dan membandingkannya? Dari versi apa fitur ini ditambahkan?
Seseorang masih menggunakan Anda MS-DOS
1
@ SomebodystillusesyouMS-DOS Pikiran pertama saya adalah memeriksa secara langsung apakah ia berfungsi - [ $(echo x | sed 's/\</y/') == "yx" ] || exit.
Kevin
2
Ini akan pecah jika salah satu elemen array mengandung karakter khusus, spasi yang paling jelas dan tak terelakkan.
Gilles 'SANGAT berhenti menjadi jahat'
1
@ SomebodystillusesyouMS-DOS Gilles benar, Anda harus mengubah penerimaan menjadi manatwork.
Kevin
0
[srikanth@myhost ~]$ sh sample.sh 

-option1 -option2 -option3

[srikanth@myhost ~]$ cat sample.sh

#!/bin/bash

my_array=(option1 option2 option3)

echo ${my_array[@]} | sed 's/\</-/g'

sumber