Saya ingin meneruskan params ke skrip bash, dd-style. Pada dasarnya, saya mau
./script a=1 b=43
memiliki efek yang sama dengan
a=1 b=43 ./script
Saya pikir saya bisa mencapai ini dengan:
for arg in "$@"; do
eval "$arg";
done
Apa cara yang baik untuk memastikan bahwa eval
aman, yaitu yang "$arg"
cocok dengan penugasan variabel statis (tanpa eksekusi kode)?
Atau adakah cara yang lebih baik untuk melakukan ini? (Saya ingin membuat ini tetap sederhana).
=
pemisah dan melakukan tugas dengan eval yang dibangun lebih hati-hati. Hanya untuk keamanan, untuk penggunaan pribadi, saya akan melakukannya seperti yang Anda lakukan.Jawaban:
Anda dapat melakukan ini di bash tanpa eval (dan tanpa pelarian buatan):
Sunting: Berdasarkan komentar oleh Stéphane Chazelas, saya menambahkan tanda pada deklarasi untuk menghindari agar variabel yang ditugaskan tidak dideklarasikan sebagai variabel array atau integer, yang akan menghindari sejumlah kasus yang
declare
akan mengevaluasi nilai bagian darikey=val
argumen. (Itu+a
Akan menyebabkan kesalahan jika variabel yang akan ditetapkan sudah dinyatakan sebagai variabel array, misalnya.) Semua kerentanan ini berkaitan dengan menggunakan sintaks ini untuk menetapkan kembali variabel yang ada (array atau integer), yang biasanya akan terkenal variabel shell.Pada kenyataannya, ini hanya sebuah instance dari kelas serangan injeksi yang akan sama-sama mempengaruhi
eval
solusi berbasis: itu akan jauh lebih baik untuk hanya mengizinkan nama argumen yang diketahui daripada secara membabi buta mengatur variabel mana saja yang kebetulan hadir dalam baris perintah. (Pertimbangkan apa yang terjadi jika baris perintah menetapkanPATH
, misalnya. Atau mengatur ulangPS1
untuk menyertakan beberapa evaluasi yang akan terjadi pada tampilan prompt berikutnya.)Daripada menggunakan variabel bash, saya lebih suka menggunakan array asosiatif dari argumen bernama, yang keduanya lebih mudah diatur, dan jauh lebih aman. Atau, itu bisa mengatur variabel bash aktual, tetapi hanya jika nama mereka dalam array asosiatif argumen yang sah.
Sebagai contoh dari pendekatan yang terakhir:
sumber
^[[:alpha:]_][[:alnum:]_]*=
?foo=
adalah satu-satunya cara untuk mengatur foo ke string kosong, jadi harus diizinkan (IMHO). Saya memperbaiki kurung, terima kasih.declare
adalah tentang sama berbahayanyaeval
(orang bahkan dapat mengatakan lebih buruk karena tidak jelas bahwa itu sama berbahayanya). Coba misalnya menyebutnya dengan'DIRSTACK=($(echo rm -rf ~))'
argumen.+x
is "not-x
".-a
= array yang diindeks,-A
= array asosiatif,-i
= variabel integer. Jadi: bukan array yang diindeks, bukan array asosiatif, bukan integer.bash
, Anda mungkin perlu menambahkan+c
untuk menonaktifkan variabel gabungan atau+F
untuk menonaktifkan variabel mengambang. Saya masih akan menggunakan dieval
mana Anda tahu di mana Anda berdiri.Yang POSIX (set
$<prefix>var
bukannya$var
untuk menghindari masalah dengan variabel khusus sepertiIFS
/PATH
...):Disebut sebagai
myscript x=1 PATH=/tmp/evil %=3 blah '=foo' 1=2
, itu akan menetapkan:sumber
solusi lcd047 di refactored dengan
DD_OPT_
awalan hardcoded :frostschutz layak mendapatkan kredit untuk sebagian besar refactoring.
Saya menempatkan ini dalam file sumber dengan sebagai variabel global:
eval "$DD_OPTS_PARSE"
melakukan semua keajaiban.Versi untuk fungsi adalah:
DD_OPTS_PARSE_LOCAL="${PARSE_AND_REMOVE_DD_OPTS/DD_OPT_/local DD_OPT_}"
Digunakan:
eval "$DD_OPTS_PARSE_LOCAL"
Saya membuat repo dari ini, lengkap dengan tes dan README.md. Kemudian saya menggunakan ini dalam bungkus Github API CLI yang saya tulis, dan saya menggunakan bungkus yang sama untuk mengatur klon github dari kata repo (bootstrap itu menyenangkan).
Melewati parameter aman untuk skrip bash hanya dalam satu baris. Nikmati. :)
sumber
*=*
dan berhenti mengganti kunci / val di mana tidak ada =. (karena Anda refactoring): Pkey
danval
, dan hanya menuliseval "${1%%=*}"=\${1#*=}
. Tapi itu sudah sejauh ini,eval "$1"
karena di @ ricideclare "$arg"
tidak akan bekerja, jelas. Waspadalah juga dalam mengatur hal-hal sepertiPATH
atauPS1
.case
. Mungkin itu tidak masalah, tapi kalau-kalau Anda tidak tahu ...Shell Bourne klasik didukung, dan shell Bash dan Korn masih mendukung, sebuah
-k
opsi. Ketika itu berlaku,dd
opsi perintah '-seperti' di mana saja pada baris perintah dikonversi secara otomatis menjadi variabel lingkungan yang diteruskan ke perintah:Agak sulit untuk meyakinkan bahwa mereka adalah variabel lingkungan; menjalankan ini bekerja untuk saya:
Yang pertama
env | grep
menunjukkan tidak ada variabel lingkungan dengan satu huruf kecil. Yang pertamabash
menunjukkan bahwa tidak ada argumen yang diteruskan ke skrip dieksekusi melalui-c
, dan lingkungan memang mengandung tiga variabel huruf tunggal. Theset +k
membatalkan-k
, dan menunjukkan bahwa perintah yang sama sekarang memiliki argumen berlalu untuk itu. (Itua=1
diperlakukan sebagai$0
naskah; Anda dapat membuktikannya juga, dengan gema yang sesuai.)Ini mencapai apa yang ditanyakan oleh pertanyaan - bahwa mengetik
./script.sh a=1 b=2
harus sama dengan mengetika=1 b=2 ./script.sh
.Perlu diketahui bahwa Anda mengalami masalah jika Anda mencoba trik seperti ini di dalam skrip:
Ini
"$@"
diperlakukan kata demi kata; itu tidak dianalisis kembali untuk menemukan variabel gaya penugasan (dalam keduanyabash
danksh
). Saya mencoba:dan hanya
already_invoked_with_minus_k
variabel lingkungan diatur dalamexec
skrip d.sumber
Usaha saya:
Ia bekerja dengan (hampir) sampah sembarang pada RHS:
sumber
shift
malah bukanshift 1
). Jika tidak terima kasih!Beberapa waktu yang lalu saya memilih
alias
untuk pekerjaan semacam ini. Inilah beberapa jawaban saya yang lain:Kadang-kadang dimungkinkan untuk memisahkan evaluasi dan pelaksanaan pernyataan tersebut. Misalnya,
alias
dapat digunakan untuk mengevaluasi dulu suatu perintah. Dalam contoh berikut ini, definisi variabel disimpan ke alias yang hanya dapat dinyatakan dengan sukses jika$var
variabel yang dievaluasi tidak mengandung byte yang tidak cocok dengan alfanumerik ASCII atau _.eval
digunakan di sini untuk menangani memohon yang barualias
dari konteks varname yang dikutip - bukan untuk tugas yang tepat. Daneval
hanya dipanggil sama sekali jikaalias
definisi sebelumnya berhasil, dan sementara saya tahu banyak implementasi yang berbeda akan menerima banyak jenis nilai untuk nama alias, saya belum menemukan shell yang akan menerima yang benar-benar kosong .Namun, definisi dalam alias adalah untuk
_$var
, dan ini untuk memastikan bahwa tidak ada nilai lingkungan signifikan yang dituliskan. Saya tidak tahu nilai lingkungan penting apa pun yang dimulai dengan _ dan biasanya ini merupakan taruhan yang aman untuk deklarasi semi-pribadi.Lagi pula, jika definisi alias berhasil, itu akan mendeklarasikan alias bernama untuk
$var
nilai. Daneval
hanya akan memanggil itualias
jika juga tidak dimulai dengan angka - yang laineval
hanya mendapatkan argumen nol. Jadi jika kedua kondisi terpenuhieval
panggilanalias
dan definisi variabel disimpan dalamalias
dibuat, setelah itu alias baru segera dihapus dari tabel hash.Yang juga bermanfaat
alias
dalam konteks ini adalah Anda dapat mencetak karya Anda.alias
akan mencetak pernyataan aman-untuk-eksekusi kembali shell yang dikutip dua kali lipat ketika ditanya.KELUARAN
sumber