Tambahkan argumen ke 'bash -c'

22

Katakanlah saya ingin menjalankan perintah melalui Bash seperti ini:

/bin/bash -c "ls -l"

Menurut halaman manual Bash, saya juga bisa menjalankannya seperti ini:

#               don't process arguments after this one
#               |   pass all unprocessed arguments to command
#               |   |
#               V   V
/bin/bash -c ls -- -l

kecuali tampaknya tidak berhasil (tampaknya diabaikan). Apakah saya melakukan sesuatu yang salah, atau apakah saya menafsirkan halaman manual salah?

Kutipan yang relevan dari manusia:

Jika opsi -c hadir, maka perintah dibaca dari string. Jika ada argumen setelah string, mereka ditugaskan ke parameter posisi, dimulai dengan $ 0.

dan

A - menandakan akhir opsi dan menonaktifkan pemrosesan opsi lebih lanjut. Setiap argumen setelah - diperlakukan sebagai nama file dan argumen.

Slartibartfast
sumber

Jawaban:

33

Anda mengartikan halaman manual salah. Pertama, bagian tentang --menandakan akhir opsi tidak relevan dengan apa yang Anda coba lakukan. The -cmenimpa sisa baris perintah dari saat itu, sehingga tidak lagi melalui penanganan pilihan bash sama sekali, yang berarti bahwa --akan melewati ke perintah, tidak ditangani oleh bash sebagai akhir pilihan penanda.

Kesalahan kedua adalah bahwa argumen tambahan ditetapkan sebagai parameter posisi pada proses shell yang diluncurkan, tidak diteruskan sebagai argumen untuk perintah. Jadi, apa yang Anda coba lakukan dapat dilakukan sebagai salah satu dari:

/bin/bash -c 'echo "$0" "$1"' foo bar
/bin/bash -c 'echo "$@"' bash foo bar

Dalam kasus pertama, meneruskan parameter echo $0dan $1secara eksplisit, dan dalam kasus kedua, menggunakan "$@"untuk memperluas normal seperti "semua parameter posisi kecuali $ 0". Perhatikan bahwa dalam hal ini kita harus melewatkan sesuatu untuk digunakan $0juga; Saya telah memilih "bash" karena itulah yang $0biasanya, tetapi hal lain akan berhasil.

Adapun alasannya dilakukan dengan cara ini, alih-alih hanya meneruskan argumen yang Anda berikan langsung ke perintah yang Anda daftarkan: perhatikan bahwa dokumentasi mengatakan "perintah s dibaca dari string", jamak. Dengan kata lain, skema ini memungkinkan Anda untuk melakukan:

/bin/bash -c 'mkdir "$1"; cd "$1"; touch "$2"' bash dir file

Tetapi, perhatikan bahwa cara yang lebih baik untuk memenuhi tujuan awal Anda mungkin dengan menggunakan envdaripada bash:

/usr/bin/env -- "ls" "-l"

Jika Anda tidak memerlukan fitur apa pun yang disediakan oleh shell, tidak ada alasan untuk menggunakannya - menggunakan envdalam hal ini akan lebih cepat, lebih sederhana, dan lebih sedikit mengetik. Dan Anda tidak perlu berpikir keras untuk memastikannya akan menangani nama file yang berisi karakter meta shell atau spasi kosong dengan aman.

godlygeek
sumber
3

Saya tidak yakin apa tujuan Anda, tetapi jika Anda hanya mencoba untuk membangun mesin Rube Goldberg - “alat, penemuan, perangkat atau peralatan yang sengaja direkayasa berlebihan atau berlebihan untuk melakukan tugas yang sangat sederhana dalam busana yang rumit ”- lalu coba

sh -c 'ls $0' -l

atau

sh -c 'ls $1' supercalifragilisticexpialidocious -l

atau bahkan

sh -c 'ls -$0' l

Anda harus bisa memahami bagaimana ini bekerja dari jawaban godlygeek.

Scott
sumber