Bash -c dengan parameter posisi


15

Biasanya, $0dalam sebuah skrip diatur ke nama skrip, atau untuk apa pun itu dipanggil sebagai (termasuk path). Namun, jika saya gunakan bashdengan -copsi, $0disetel ke argumen pertama yang diberikan setelah string perintah:

bash -c 'echo $0 ' foo bar 
# foo 

Efeknya, sepertinya parameter posisi telah digeser, tetapi termasuk $0. Namun shiftdalam string perintah tidak mempengaruhi $0(seperti biasa):

bash -c 'echo $0; shift; echo $0 ' foo bar
# foo
# foo

Mengapa perilaku yang tampaknya aneh ini untuk string perintah? Perhatikan bahwa saya mencari alasan, alasannya, di balik penerapan perilaku aneh tersebut.


Orang bisa berspekulasi bahwa string perintah seperti itu tidak akan membutuhkan $0parameter seperti yang biasanya didefinisikan, jadi untuk ekonomi juga digunakan untuk argumen normal. Namun, dalam hal itu perilaku shiftaneh. Kemungkinan lain adalah yang $0digunakan untuk mendefinisikan perilaku program (ala bashdisebut sebagai shatau vimdisebut sebagai vi), tetapi itu tidak bisa, karena di $0sini hanya terlihat dalam string perintah dan bukan oleh program yang dipanggil di dalamnya. Saya tidak bisa memikirkan kegunaan lain untuk apa $0, jadi saya bingung menjelaskan hal ini.


Sebagai catatan, saya telah melihat penggunaan -untuk $0argumen sebagai idiom, seperti di sh -c 'foo $1 $2' - a b. Dengan cara ini terlihat cukup normal (setelah Anda mengetahui apa -artinya itu)
Volker Siegel

Anda juga dapat echo 'echo the other side of this pipe globs "$@"' | sh -s -- *, meskipun, sayangnya, $0umumnya bukan parameter yang -sdapat diatur dengan opsi tream ... Ini dapat digunakan dalam banyak cara yang sama pada xargsumumnya. Dan lainnya selain itu.
mikeserv

@VolkerSiegel Lebih normal akan --, maka itu bisa saja memiliki interpretasi biasa 'dari sini mulai argumen', terlihat di beberapa program lain. Kemudian lagi, itu bisa membingungkan mereka yang tidak terbiasa -cuntuk berpikir --sebenarnya memiliki interpretasi itu.
muru

Jawaban:


10

Itu memberi Anda kesempatan untuk menetapkan / memilih $0saat menggunakan skrip inline. Kalau tidak, $0akan begitu saja bash.

Maka Anda bisa melakukannya misalnya:

$ bash -c 'wc -c < "${1?}"' getlength foo
4
$ bash -c 'wc -c < "${1?}"' getlength bar
getlength: bar: No such file or directory
$ bash -c 'wc -c < "${1?}"' getlength
getlength: 1: parameter null or not set

Tidak semua kerang digunakan untuk melakukan itu. Shell Bourne melakukannya. Shell Korn (dan Almquist) memilih parameter pertama yang dituju $1. POSIX akhirnya menggunakan cara Bourne, jadi kshdan ashturunannya dikembalikan ke sana nanti (lebih lanjut tentang itu di http://www.in-ulm.de/~mascheck/various/find/#shell ). Itu berarti bahwa untuk waktu yang lama untuk sh(yang tergantung pada sistem didasarkan pada Bourne, Almquist atau Korn shell), Anda tidak tahu apakah argumen pertama masuk $0atau $1, jadi untuk portabilitas, Anda harus melakukan hal-hal seperti:

sh -c 'echo foo in "$1"' foo foo

Atau:

sh -c 'shift "$2"; echo txt files are "$@"' tentative-arg0 3 2 *.txt

Untungnya, POSIX telah menentukan perilaku baru di mana argumen pertama masuk $0, jadi kita sekarang bisa melakukan:

sh -c 'echo txt files are "$@"' meaningful-arg0-for-error *.txt

Aku hanya berlari: bash -c 'echo txt files are "$@"' meaningful-arg0-for-error *.txtpada Ubuntu 14.04, bash version 4.3.11(1)-release, dan aku: txt files are *.txt. Oo
muru

2
@muru, yang benar (dan Anda mungkin tidak memiliki txtfile di direktori saat ini). Lihat jugabash -c 'echo "${1?}"' foo
Stéphane Chazelas

Ah iya. Itu contoh praktis yang berguna.
muru

1
sh -c 'shift "$2"; echo txt files are "$@"' tentative-arg0 3 2 *.txtadalah inventif fantastis!
iruvar

Atau Anda menggunakan solusi yang sangat kuat (disarankan oleh Stéphane Chazelas di comp.unix.shell) SHELL -c 'shift $1; command' 2 1 arg1 arg2 ... haha ...
mikeserv

3

Perilaku ini didefinisikan oleh POSIX :

sh -c command_name [argumen ...]

Baca perintah dari operan command_string. Tetapkan nilai parameter khusus 0 (lihat Parameter Khusus ) dari nilai operand perintah_name dan parameter posisi ($ 1, $ 2, dan seterusnya) secara berurutan dari operan argumen yang tersisa.

Adapun mengapa Anda menginginkan perilaku itu: ini memperlancar jarak antara skrip dan -cstring. Anda dapat langsung mengkonversi antara keduanya tanpa perubahan perilaku. Daerah lain mengandalkan ini identik.

Ini juga sejalan dengan cara kerja argumen program secara umum: ini pada akhirnya bermuara pada memanggil salah satu execfungsi, di mana argumen pertama yang disediakan juga $0, dan sama-sama umum argumen itu sama dengan executable yang Anda jalankan. Namun, kadang-kadang, Anda menginginkan nilai khusus di sana, dan tidak ada cara lain untuk mendapatkannya. Mengingat bahwa ada argumen, itu harus memetakan ke sesuatu, dan pengguna harus dapat mengatur apa itu.

Konsistensi ini (dan kemungkinan kecelakaan historis) mengarah pada situasi yang Anda temukan.


Bisakah Anda memberikan contoh (yang diharapkan di dunia nyata) dari para kedua?
muru

Hati-hati dengan analogi dengan argv[0]. $0hanya diatur ke yang argv[0]diteruskan ke execve()saat suka shatau bash. Untuk skrip, $0disetel ke jalur yang diberikan sebagai argumen 1, 2 ... ke interpreter (dan untuk skrip yang dieksekusi secara langsung, yang berasal dari argumen jalur pertama yang dieksekusi ()).
Stéphane Chazelas
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.