Saya ingin menyimpan perintah untuk digunakan di lain waktu dalam variabel (bukan output dari perintah, tetapi perintah itu sendiri)
Saya memiliki skrip sederhana sebagai berikut:
command="ls";
echo "Command: $command"; #Output is: Command: ls
b=`$command`;
echo $b; #Output is: public_html REV test... (command worked successfully)
Namun, ketika saya mencoba sesuatu yang lebih rumit, gagal. Misalnya kalau saya bikin
command="ls | grep -c '^'";
Outputnya adalah:
Command: ls | grep -c '^'
ls: cannot access |: No such file or directory
ls: cannot access grep: No such file or directory
ls: cannot access '^': No such file or directory
Tahu bagaimana saya bisa menyimpan perintah seperti itu (dengan pipa / beberapa perintah) dalam variabel untuk digunakan nanti?
Jawaban:
Gunakan eval:
sumber
backticks
. y = $ (eval $ x) mywiki.wooledge.org/BashFAQ/082eval
adalah praktik yang dapat diterima hanya jika Anda mempercayai konten variabel Anda. Jika Anda menjalankan, katakanlah,x="ls $name | wc"
(atau bahkanx="ls '$name' | wc"
), kode ini adalah jalur cepat ke kerentanan injeksi atau eskalasi hak istimewa jika variabel itu dapat disetel oleh seseorang dengan hak istimewa yang lebih sedikit. (Mengulangi semua subdirektori di/tmp
, misalnya? Sebaiknya Anda mempercayai setiap pengguna di sistem untuk tidak memanggilnya$'/tmp/evil-$(rm -rf $HOME)\'$(rm -rf $HOME)\'/'
).eval
adalah magnet bug besar yang tidak pernah direkomendasikan tanpa peringatan tentang risiko perilaku penguraian yang tidak terduga (bahkan tanpa string berbahaya, seperti dalam contoh @ CharlesDuffy). Misalnya, cobax='echo $(( 6 * 7 ))'
lalueval $x
. Anda mungkin berharap untuk mencetak "42", tetapi mungkin tidak. Bisakah Anda menjelaskan mengapa itu tidak berhasil? Bisakah Anda menjelaskan mengapa saya berkata "mungkin"? Jika jawaban atas pertanyaan-pertanyaan itu tidak jelas bagi Anda, jangan pernah menyentuhnyaeval
.set -x
sebelumnya untuk mencatat perintah yang dijalankan, yang akan membuatnya lebih mudah untuk melihat apa yang terjadi.Jangan tidak menggunakan
eval
! Ini memiliki risiko besar untuk memperkenalkan eksekusi kode arbitrer.BashFAQ-50 - Saya mencoba untuk meletakkan perintah dalam variabel, tetapi kasus yang kompleks selalu gagal.
Memasukkannya ke dalam array dan memperluas semua kata dengan tanda kutip ganda
"${arr[@]}"
untuk tidak membiarkanIFS
perpecahan kata-kata karena Firman Memisahkan .dan melihat isi dari array di dalamnya. The
declare -p
memungkinkan Anda melihat isi dalam array dengan masing-masing parameter perintah di indeks terpisah. Jika satu argumen seperti itu berisi spasi, mengutip di dalam sambil menambahkan ke array akan mencegahnya terpecah karena Pemisahan Kata.dan jalankan perintah sebagai
(atau) semuanya menggunakan
bash
fungsi untuk menjalankan perintah,dan menyebut fungsinya sebagai adil
POSIX
sh
tidak memiliki larik, jadi yang paling dekat yang bisa Anda lakukan adalah membuat daftar elemen dalam parameter posisi. Berikutsh
cara POSIX untuk menjalankan program emailPerhatikan bahwa pendekatan ini hanya dapat menangani perintah sederhana tanpa pengalihan. Ia tidak dapat menangani pengalihan, pipeline, for / while loop, if statement, dll
Kasus penggunaan umum lainnya adalah saat menjalankan
curl
beberapa kolom header dan payload. Anda selalu dapat menentukan args seperti di bawah ini dan memanggilcurl
konten array yang diperluasContoh lain,
Sekarang variabel telah ditentukan, gunakan array untuk menyimpan perintah Anda args
dan sekarang lakukan ekspansi yang dikutip dengan benar
sumber
Command=('echo aaa | grep a')
dan"${Command[@]}"
, berharap itu benar-benar menjalankan perintahecho aaa | grep a
. Tidak. Saya ingin tahu apakah ada cara yang aman untuk menggantieval
, tetapi tampaknya setiap solusi yang memiliki kekuatan yang samaeval
bisa berbahaya. Bukan?Command() { echo aaa | grep a; }
- setelah itu Anda bisa menjalankanCommand
, atauresult=$(Command)
, atau sejenisnya.Dengan menggunakan metode ini, perintah segera dievaluasi dan nilai kembaliannya disimpan.
Sama dengan backtick
Menggunakan eval di
$(...)
tidak akan membuatnya dievaluasi nantiMenggunakan eval, ini dievaluasi saat
eval
digunakanDalam contoh di atas, jika Anda perlu menjalankan perintah dengan argumen, letakkan di string yang Anda simpan
Untuk skrip bash ini jarang relevan, tapi satu catatan terakhir. Berhati-hatilah
eval
. Evaluasi hanya string yang Anda kontrol, tidak pernah string yang berasal dari pengguna yang tidak tepercaya atau dibuat dari input pengguna yang tidak tepercaya.sumber
eval $stored_date
mungkin cukup baik jikastored_date
hanya berisidate
, tetapieval "$stored_date"
jauh lebih dapat diandalkan. Jalankanstr=$'printf \' * %s\\n\' *'; eval "$str"
dengan dan tanpa tanda kutip di sekitar final"$str"
sebagai contoh. :)Untuk bash, simpan perintah Anda seperti ini:
Jalankan perintah Anda seperti ini:
sumber
Saya mencoba berbagai metode berbeda:
Keluaran:
Seperti yang Anda lihat, hanya yang ketiga, yang
"$@"
memberikan hasil yang benar.sumber
Berhati-hatilah saat mendaftarkan pesanan dengan:
X=$(Command)
Yang ini masih dijalankan Bahkan sebelum dipanggil. Untuk memeriksa dan mengkonfirmasi ini, Anda dapat melakukan:
sumber
sumber
Tidak perlu menyimpan perintah dalam variabel meskipun Anda perlu menggunakannya nanti. jalankan saja seperti biasa. Jika Anda menyimpan dalam variabel, Anda akan memerlukan semacam
eval
pernyataan atau menjalankan beberapa proses shell yang tidak perlu untuk "mengeksekusi variabel Anda".sumber
var='*.txt'; find . -name "$var"