Shell POSIX: apakah `$` kehilangan makna khususnya jika itu adalah karakter terakhir dalam sebuah kata?

17

Di abu, lari dan bash, ketika saya lari

$ echo ab$

ia kembali

ab$

Apakah perilaku ini ditentukan oleh POSIX atau hanya konvensi umum di shell yang sesuai dengan POSIX? Saya tidak dapat menemukan apa pun di halaman POSIX Shell Command Language yang menyebutkan perilaku ini.

Harold Fischer
sumber
4
Pertanyaan yang lebih baik adalah "Apakah $ mendapatkan makna khusus jika itu adalah karakter terakhir dalam sebuah kata?" Tidak ada makna khusus yang diberikan untuk $; ini digunakan untuk memperkenalkan beberapa, tetapi berbeda, ekspansi, seperti ekspansi parameter ${...}, penggantian perintah $(...), dan ekspresi aritmatika $((...)). Beberapa shell memperkenalkan konteks tambahan, seperti kshvarian substitusi-perintah x=${ echo foo; echo bar;}(yang berbeda dari standar $(...)dengan tidak mengeksekusi perintah dalam subkulit).
chepner
@chepner Maukah Anda mempertimbangkan perbedaan pendapat antara Issac dan Michael Homer? Jawaban mereka secara eksplisit saling bertentangan
Harold Fischer
1
Saya setuju dengan interpretasi Michael Homer; shell bahkan tidak mulai khawatir tentang ekspansi sampai setelah parsing selesai, sehingga dalam satu kata ab$, tidak ada karakter berikut $, apakah itu "diikuti" oleh karakter null pada input string asli atau spasi dalam kasus seperti echo ab$ foo; spasi asli yang tidak dikutip telah dikenali dan dibuang setelah diuraikan.
chepner

Jawaban:

10

$tidak memiliki arti khusus dengan sendirinya (coba echo $), hanya ketika digabungkan dengan karakter lain setelahnya dan membentuk ekspansi, misalnya $var(atau ${var}) $(util),, $((1+2)).

The $mendapat makna "khusus" sebagai mendefinisikan ekspansi dalam standar POSIX di bawah bagian Pengakuan Token :

Jika karakter saat ini adalah tanda kutip $atau `, shell harus mengidentifikasi awal setiap kandidat untuk ekspansi parameter, penggantian perintah, atau ekspansi aritmatika dari urutan karakter tanpa tanda kutip pengantar mereka: $atau ${, $(atau `, dan $((, masing-masing. Shell harus membaca input yang cukup untuk menentukan ujung unit yang akan diperluas ( seperti dijelaskan dalam bagian yang dikutip). Saat memproses karakter, jika instance ekspansi atau penawaran ditemukan bersarang di dalam substitusi, shell akan memprosesnya secara rekursif dengan cara yang ditentukan untuk konstruk yang ditemukan. Karakter yang ditemukan dari awal substitusi sampai akhir, memungkinkan untuk setiap rekursi yang diperlukan untuk mengenali konstruksi yang disematkan, harus dimasukkan tanpa dimodifikasi dalam token hasil, termasuk setiap operator atau kutipan substitusi yang melekat atau tertutup. Token tidak boleh dibatasi pada akhir penggantian.

Jadi, jika $tidak membentuk ekspansi, aturan parsing lain berlaku:

Jika karakter sebelumnya adalah bagian dari kata, karakter saat ini harus ditambahkan ke kata itu.

Itu menutupi ab$string Anda .

Dalam kasus sendirian $("kata baru" akan menjadi $dengan sendirinya):

Karakter saat ini digunakan sebagai awal kata baru.

The makna dari kata yang dihasilkan mengandung $yang tidak ekspansi standar secara eksplisit didefinisikan sebagai tidak ditentukan oleh POSIX.

Perhatikan juga bahwa $ini adalah karakter terakhir $$, tetapi ini juga merupakan variabel yang menyimpan PID shell saat ini. Di bash, !$dapat memanggil ekspansi sejarah (argumen terakhir dari perintah sebelumnya). Jadi secara umum, tidak, $bukan tanpa makna pada akhir kata yang tidak dikutip, tetapi pada akhir kata itu setidaknya tidak menunjukkan ekspansi standar.

Kusalananda
sumber
7

Bergantung pada situasi yang tepat, ini bisa secara eksplisit tidak ditentukan (sehingga implementasi dapat melakukan apa yang mereka mau) atau diharuskan untuk terjadi saat Anda mengamati. Dalam skenario persis Anda echo ab$, POSIX mengamanatkan keluaran "ab $" yang Anda amati dan tidak ditentukan . Ringkasan singkat dari semua kasus yang berbeda ada di akhir.

Ada dua elemen: pertama mencari kata-kata, dan kemudian menafsirkan kata-kata itu.


Tokenisasi

Tokenisasi POSIX mensyaratkan bahwa a $yang bukan awal dari perluasan parameter yang valid , substitusi perintah , atau substitusi aritmatika untuk dianggap sebagai bagian literal dari WORDtoken yang sedang dibangun. Ini karena aturan 5 ("Jika karakter saat ini adalah tanda kutip $atau `, shell harus mengidentifikasi awal dari setiap kandidat untuk ekspansi parameter, penggantian perintah, atau ekspansi aritmatika dari urutan karakter tanpa tanda kutip pengantar mereka: $atau ${, $(atau `, dan $((, masing-masing" ) tidak berlaku, karena tidak ada ekspansi yang layak di sana. Perluasan parameter memerlukan nama yang valid untuk muncul di sana, dan nama yang kosong tidak valid.

Karena aturan ini tidak berlaku, kami terus mengikuti hingga kami menemukannya. Dua kandidat adalah # 8 ("Jika karakter sebelumnya adalah bagian dari sebuah kata, karakter saat ini akan ditambahkan ke kata itu.") Dan # 10 ("Karakter saat ini digunakan sebagai awal dari kata baru.") , yang berlaku untuk echo a$dan echo $masing - masing.

Ada juga kasus ketiga dari formulir echo a$+byang jatuh melalui celah yang sama, karena +bukan nama parameter khusus. Yang ini akan kita bahas nanti, karena memicu berbagai bagian aturan.

Dengan demikian spesifikasi mensyaratkan bahwa kata $tersebut dianggap sebagai bagian dari kata secara sintaksis, dan kemudian dapat diproses lebih lanjut di kemudian hari.


Perluasan kata

Setelah input diuraikan dengan cara ini, dengan yang $termasuk dalam kata, ekspansi kata diterapkan ke setiap kata yang telah dibaca. Setiap kata diproses secara individual .

Ditetapkan bahwa :

Jika tanda kutip '$' diikuti oleh karakter yang bukan salah satu dari yang berikut:

  • Karakter numerik
  • Nama salah satu parameter khusus (lihat Parameter Khusus )
  • Karakter pertama yang valid dari nama variabel
  • A <left-curly-bracket>('{')
  • SEBUAH <left-parenthesis>

hasilnya tidak ditentukan.

"Tidak ditentukan" adalah istilah khusus di sini yang berarti

  1. Shell yang menyesuaikan dapat memilih perilaku apa pun dalam kasus ini
  2. Aplikasi yang sesuai tidak dapat mengandalkan perilaku tertentu

Dalam contoh Anda, echo ab$, yang $ tidak diikuti oleh setiap karakter , sehingga aturan ini tidak berlaku dan hasil yang tidak ditentukan tidak dipanggil. Tidak ada ekspansi yang dipicu oleh $, sehingga benar-benar ada dan dicetak.

Di mana itu akan berlaku dalam kasus ketiga kami dari atas: echo a$+b. Berikut $ini diikuti oleh +yang bukan nomor, parameter khusus ( @, *, #, ?, -, $, !, atau 0), mulai dari variabel nama (garis bawah atau abjad dari set karakter portable ), atau salah satu dari tanda kurung. Dalam kasus ini, perilaku tidak ditentukan: shell yang sesuai diizinkan untuk menciptakan parameter khusus yang dipanggil +untuk memperluas , dan aplikasi yang sesuai tidak boleh berasumsi bahwa shell tidak . Shell dapat melakukan hal lain yang disukainya, termasuk melaporkan kesalahan.

Sebagai contoh, zsh, termasuk dalam mode POSIX-nya, mengartikan $+bsebagai " bset variabel " dan menggantikan 1 atau 0 sebagai gantinya. Ini juga memiliki ekstensi untuk ~dan =. Ini adalah perilaku yang sesuai.

Tempat lain yang bisa terjadi adalah echo "a$ b". Sekali lagi, shell diizinkan untuk melakukan $apa yang diinginkan , dan Anda sebagai penulis naskah harus melarikan diri jika Anda ingin output literal. Jika tidak, ini mungkin berhasil, tetapi Anda tidak dapat mengandalkannya. Ini adalah huruf absolut dari spesifikasi, tetapi saya tidak berpikir granularity semacam ini dimaksudkan atau dipertimbangkan.


Singkatnya

  • echo ab$: output literal, ditentukan sepenuhnya
  • echo a$ b: output literal, ditentukan sepenuhnya
  • echo a$ b$: output literal, ditentukan sepenuhnya
  • echo a$b: perluasan parameter b, ditentukan sepenuhnya
  • echo a$-b: perluasan parameter khusus -, ditentukan sepenuhnya
  • echo a$+b: perilaku yang tidak ditentukan
  • echo "a$ b": perilaku yang tidak ditentukan

Untuk a $di akhir kata, Anda diizinkan untuk mengandalkan perilaku dan itu harus diperlakukan secara harfiah dan diteruskan ke echoperintah sebagai bagian dari argumennya. Itu adalah persyaratan kesesuaian pada shell.

Michael Homer
sumber
Komentar bukan untuk diskusi panjang; percakapan ini telah dipindahkan ke obrolan .
terdon
@MichaelHomer Apakah echo $juga literal dan ditentukan sepenuhnya?
Harold Fischer
@HaroldFischer Ya
Michael Homer
Di mana echo "$"dan echo "a b$"jatuh?
Harold Fischer