Apakah ekspansi parameter pada $ @ tidak didukung oleh shell sh?

8

Saya memposting jawaban untuk pertanyaan di AU, dan saya menemukan bahwa ekspansi parameter $@tidak berfungsi dengan shshell:

<infile xargs -d'\n' sh -c 'echo "${@%%/*}"' _

tetapi berfungsi dengan baik di bash. Apakah ini perilaku shshell yang diharapkan, dan bagaimana saya bisa melakukan ekspansi di sana?

Selain itu, saya tahu bahwa dengan -n1opsi xargssaya hanya dapat meneruskan satu baris ke perintah pada satu waktu, tetapi saya tertarik pada apakah shdapat memperluas $@:

<infile xargs -d'\n' -n1 sh -c 'echo "${0%%/*}"'

infile mengandung:

A1 /B1/C1
A 2/B2/C2
A3/B3/C3
αғsнιη
sumber

Jawaban:

12

Yap, tanda hubung tampaknya kurang berguna di sini. Meskipun itu tidak salah, sebenarnya, seperti ${@%...}yang tidak ditentukan oleh POSIX :

Empat varietas berikut ekspansi parameter menyediakan untuk pemrosesan substring. [...] Jika parameternya adalah ' #', ' *', atau ' @', hasil ekspansi tidak ditentukan.

Anehnya, tampaknya jika ekspansi seperti itu mengubah akhir dari satu parameter posisi, ia menjatuhkan yang berikut ini. Tetapi tidak jika itu tidak benar-benar mengubah akhirnya:

$ dash -c 'set -- foo bar; printf "<%s>\n" "${@%o}";'
<fo>
$ dash -c 'set -- foo bar; printf "<%s>\n" "${@%x}";'
<foo>
<bar>
$ dash -c 'set -- foo bar doo; printf "<%s>\n" "${@%r}";'
<foo>
<ba>

Bash, ksh dan Zsh semuanya tampaknya menangani "${@#...}"dan "${@%...}"dengan memproses setiap parameter posisi secara independen, yang tampaknya berguna untuk dilakukan.

Saya kira solusi nyata untuk dashmembuat modifikasi satu argumen pada satu waktu:

for x in "$@"; do echo "${x%%/*}"; done

Untuk apa nilainya, perilaku ekspansi penghapusan awalan / akhiran yang digunakan $*juga bervariasi antara shell. Bash dan ksh tampaknya memodifikasi parameter terlebih dahulu dan bergabung dengan mereka setelah itu, sementara Zsh dan dash bergabung dengan parameter terlebih dahulu dan memodifikasi string yang digabungkan:

$ zsh -c 'set -- ax bx; printf "<%s>\n" "${*%%x*}";'
<a>
$ bash -c 'set -- ax bx; printf "<%s>\n" "${*%%x*}";'
<a b>
ilkkachu
sumber
suara shberpikir $@adalah parameter tunggal untuk seluruh file (atau akan pecah menjadi beberapa jika melebihi ARG_MAX) dan melakukan ekspansi pada satu-satunya argumen.
αғsнιη
1
Perhatikan juga bahwa pdksh dan turunannya memberi Anda Bad substitutionkesalahan pada kode itu. Sebab ${*%pattern}, Anda melihat beberapa variasi dalam perilaku dalam hal-hal seperti"$shell" -c 'printf "<%s>\n" "${*%x*}"' sh ax by
Stéphane Chazelas
1
@ αғsнιη, tidak sesederhana itu. perhatikan contoh kedua di mana ekspansi meninggalkan parameter posisi sebagai kata-kata yang terpisah. Dan saya tidak berpikir ARG_MAXmasuk ke dalamnya, pemrosesan itu internal ke shell.
ilkkachu