Saya memiliki perintah yang disimpan dalam variabel. Mari kita anggap variabel $i
memiliki nilai:
cat -nT index.php |grep 'someregex'
Ketika saya mencoba menjalankan variabel di atas dengan mengetiknya $i
gagal karena shell mencoba mengeksekusi seluruh variabel sebagai satu perintah. Saya juga mencoba menggunakan eval($i)
dan memasukkan $i
backticks.
Bagaimana saya bisa membuat shell mengeksekusi $i
seolah-olah itu adalah perintah? Dan mengapa itu tidak bekerja sama dengan.
$i='echo hi'; $i
Apakah karena saya harus memilah-milah dalam tanda kutip tunggal? (Karena Anda tidak dapat membuat sarang mereka.) Saat ini solusi saya adalah
echo $i > /foo; . /foo
Tapi saya tidak ingin membuat file hanya untuk ini, hanya untuk menghapusnya nanti.
Yang saya maksud dengan "Saya meretas dalam tanda kutip tunggal adalah yang saya lakukan:
$i='cat index.php | grep -P '"'"'MYREGEXHERE'"'"
Jawaban:
Jawaban singkat: lihat BashAQ # 50: Saya mencoba untuk menempatkan perintah dalam variabel, tetapi kasus kompleks selalu gagal! .
Jawaban panjang: itu karena urutan di mana bash mem-parsing baris perintah. Secara khusus, ini mencari hal-hal seperti pipa dan pengalihan sebelum memperluas nilai variabel, dan tidak kembali dan mencari kembali pipa dll dalam nilai yang diperluas. Pada dasarnya, variabel bisa diganti sekitar setengah jalan melalui proses penguraian, sehingga nilainya hanya akan diurai setengah sebelum dieksekusi.
Untuk mengatasi ini, Anda perlu menjawab pertanyaan @ slhck: mengapa perintah disimpan dalam variabel? Apa masalah sebenarnya yang Anda coba selesaikan? Bergantung pada tujuan sebenarnya, ada sejumlah solusi yang mungkin:
Jangan menyimpannya dalam variabel, jalankan saja secara langsung. Menyimpan perintah untuk digunakan nanti itu rumit, dan jika Anda tidak benar-benar perlu, jangan lakukan.
Gunakan fungsi alih-alih variabel. Lagipula itulah gunanya:
Kerugian utama dari ini adalah bahwa Anda tidak dapat membuat fungsi secara dinamis - Anda tidak dapat memasukkan atau mengecualikan kode dari fungsi secara kondisional (meskipun fungsi itu sendiri dapat memiliki elemen kondisional yang dipilih saat dijalankan).
Gunakan
eval
. Ini harus dianggap sebagai upaya terakhir, karena mudah untuk mendapatkan perilaku yang tidak terduga. Ini pada dasarnya menjalankan perintah melalui pass parsing penuh lain, sehingga semua pipa dll mendapatkan makna penuh - tetapi itu juga berarti bahwa bagian dari perintah yang Anda pikir hanya data juga akan diurai dan mungkin dieksekusi. Nama file yang mengandung karakter meta shell (pipa, titik koma, kutipan / apostrof, dll) dapat memiliki efek aneh dan terkadang berbahaya. Jika Anda menggunakannyaeval
, setidaknya kutip dua kali string, jika tidak, isinya pada dasarnya diurai satu setengah kali, bahkan dengan hasil yang lebih aneh.EDIT: Pendekatan store-a-command-in-a-variable standar lainnya adalah menggunakan array alih-alih variabel sederhana. Ini memungkinkan Anda menyimpan perintah dengan argumen kompleks (mis. Berisi spasi) tanpa masalah, tetapi tidak akan menyimpan hal-hal seperti pipa dan arahan ulang. Jadi, pendekatan array tidak akan berguna dalam kasus khusus ini.
sumber
eval
metode ini. Ini menghentikan saya dari mengajukan pertanyaan yang sama :). Saya memiliki sesuatu sepertisudo rsync -aAHXi -n --delete-excluded --exclude={"/dev/*","/proc/*","/sys/*","/tmp/*","/run/*","/lost+found","/mnt/DATA/*","/var/log/*","/var/swap","/var/cache/apt/archives/*.deb"} -e ssh root@piac_wireless:/ /home/mrx/Docs/RPi/backup/piac/piac_usb-root
itu yang tidak mengeksekusi pengecualian dengan benar.eval
ini - ada terlalu banyak cara untuk salah. Array akan menjadi cara yang lebih baik untuk melakukan ini. Lihat di sini , di sini , dan di sini untuk contoh.Ini seharusnya bekerja:
Waspadalah yang
eval
memperkenalkan potensi kerentanan dan situasi perilaku yang tidak terduga sehingga harus digunakan, jika pernah, dengan perhatian ekstra.sumber
eval
, Anda benar-benar perlu menggunakan tanda kutip ganda (eval "$i"
) untuk menghindari efek ekstra-ekstra-aneh. Misalnya, coba ini dengana="cat -nT index.php |grep ' .* '"
(yaitu regex harus mencocokkan dua spasi dengan urutan karakter di antara mereka) dan lihat apa yang sebenarnya terjadi. Untuk kredit tambahan, jelaskan mengapa itu terjadi.Saat mendeklarasikan variabel, Anda tidak harus menggunakan tanda dolar sebagai awalan.
Coba ini:
sumber