Mengapa grup perintah brace membutuhkan spasi setelah brace pembuka di POSIX Shell Grammar?

10

TL; DR : Mengapa kelompok kurung POSIX membutuhkan spasi setelah {kata yang dipesan tetapi subkulit tidak setelah kata yang dipesan (?

Tata bahasa shell POSIX mendefinisikan grup brace dan subkulit sebagai berikut

brace_group      : Lbrace compound_list Rbrace

subshell         : '(' compound_list ')'

Sekarang, jika kita membaca itu secara harfiah, spasi adalah signifikan. Ini berarti bahwa harus ada ruang yang menggambarkan kurung kurawal buka dan tutup seperti pada

{ echo hello world; }

( echo hello world )

Ini juga akan sejajar dengan definisi Perintah Senyawa :

Setiap perintah majemuk ini memiliki kata yang dilindungi atau operator kontrol di awal, dan terminator yang sesuai kata atau operator di akhir.

Namun apa yang tidak masuk akal adalah mengapa (list)dan ( list )bekerja dengan baik (ruang setelah (itu tidak diperlukan), namun ekspansi brace harus memiliki ruang terdepan, yaitu {echo hello;}tidak akan bekerja.

Tentu saja kata yang dilindungi dianggap sebagai kata shell akan masuk akal membutuhkan ruang setelah itu untuk menyelaraskan dengan konsep pemisahan bidang , namun definisi itu sendiri tidak menyebutkan spasi. Lebih lanjut, jika {dan (keduanya dianggap kata-kata yang dicadangkan oleh definisi POSIX dari perintah majemuk, mengapa mereka diperlakukan secara berbeda dalam hal karakter ruang setelah kata-kata yang dipesan ini? Sekarang, ksh (1) manual menyatakan:

Kata-kata, yang merupakan urutan karakter, dibatasi oleh karakter spasi putih yang tidak dikutip (spasi, tab, dan baris baru) atau meta-karakter (<,>, |,;, & & (()))

Dengan kata lain, masuk akal bahwa ksh akan dikenali (sebagai pembatas kata, di mana kata pertama akan menjadi perintah atau penugasan variabel. POSIX, namun tampaknya tidak menyebutkan (sebagai meta-karakter. Satu-satunya penjelasan yang mungkin saya temukan sejauh tata bahasa POSIX berjalan adalah yang {dianggap sebagai "token", di mana (tidak terdaftar sebagai satu.

/* These are reserved words, not operator tokens, and are
   recognized when reserved words are recognized. */


%token  Lbrace    Rbrace    Bang
/*      '{'       '}'       '!'   */

Jadi, apa alasan yang tepat untuk perbedaan ini?

Catatan Jawaban yang Diterima:

  • Tanda centang yang diterima diterima untuk jawaban Ishak karena memberikan q uote membentuk standar itu sendiri yang langsung menjawab pertanyaan saya:

    Misalnya, '(' dan ')' adalah operator kontrol, sehingga tidak <space>diperlukan dalam (daftar). Namun, '{' dan '}' dicadangkan kata dalam {list;}, sehingga dalam hal ini yang memimpin <space>dan <semicolon>diperlukan.

  • Menerima jawaban Kusalananda . Jawaban Kusalananda membahas apa yang saya butuhkan, meskipun sebagian besar dari sudut pandang informal dan intuitif; itu menunjukkan {kata yang dilindungi undang-undang dan (operator. Michael Homer juga mencatat hal yang sama dalam komentar - yang menyatakan definisi Compound Command (penekanan ditambahkan):

    Setiap perintah majemuk ini memiliki kata dilindungi atau operator kontrol di awal

  • {didefinisikan sebagai kata yang dilindungi undang-undang, mirip dengan foratau while, tercantum dalam Shell Grammar (lihat blok kode terakhir dalam pertanyaan)

  • Bagian 2.9 menyatakan (penekanan ditambahkan):

    Secara khusus, representasi termasuk spasi antara token di beberapa tempat di mana <blank>s tidak diperlukan (ketika salah satu token adalah operator).

  • Sementara standar tidak secara eksplisit mendefinisikan (sebagai operator, (disebut sebagai operator; khususnya, bagian 2.9.2 mengatakan

    Jika pipa dimulai dengan kata yang dipesan! dan perintah1 adalah perintah subkulit, aplikasi harus memastikan bahwa (operator pada awal perintah1 dipisahkan dari! oleh satu atau lebih karakter. Perilaku kata yang dilindungi undang-undang! segera diikuti oleh (operator tidak ditentukan.

  • Pertanyaan tentang Stack Overflow oleh Digital Trauma menunjukkan Bagian 2.4 tentang Kata-Kata Cadangan:

    Pengakuan ini hanya akan terjadi ketika tidak ada karakter yang dikutip dan ketika kata tersebut digunakan sebagai:

    -Kata pertama dari sebuah perintah

  • Seperti yang disebutkan dalam jawaban Kusalananda "Ruang yang ditunjukkan dalam tata bahasa POSIX bukan ruang yang perlu ada di dalam data input shell, tetapi hanya cara menampilkan tata bahasa itu sendiri. Adalah fakta bahwa kawat gigi disediakan kata-kata yang menyiratkan bahwa mereka harus dikelilingi oleh spasi putih "Seperti yang disebutkan oleh Michael Homer dalam komentar:" Jika ruang itu signifikan dalam hak mereka sendiri, mereka harus terdaftar dalam produksi "

Kasus ditutup.

Sergiy Kolodyazhnyy
sumber
3
Jika ruang signifikan dalam hak mereka sendiri, mereka harus terdaftar dalam produksi.
Michael Homer
2
"Lebih lanjut, jika {dan (keduanya dianggap sebagai kata-kata yang dilindungi oleh definisi perintah gabungan POSIX" lih. "Setiap perintah majemuk ini memiliki kata yang dilindungi atau operator kontrol di awal".
Michael Homer
2
@SergiyKolodyazhnyy Saya percaya maksudnya jika ruang itu signifikan, tata bahasa harus menyertakan karakter ruang eksplisit ( ' '). Sebaliknya, spasi tersirat oleh token apa kata.
Kusalananda
2
Definisi spesifikasi kelas token adalah ... canggung, untuk sedikitnya. Seluruh tata bahasa sangat mengerikan dan spec menggabungkan berbagai hal dalam teks prosa (kadang-kadang secara implisit!), Dalam aturan prosa mendahului tata bahasa, dan dalam tata bahasa itu sendiri. Sangat tidak bisa dipahami jika Anda belum tahu jawabannya dan bekerja mundur. Semua aturan leksikal didefinisikan mundur, berdasarkan apa yang memulai token baru, daripada menggambarkan apa yang mengandung token itu. Hanya berantakan di sekitar.
Michael Homer
1
@Sergiy dalam tata bahasa formal, produksi (atau aturan produksi) menjelaskan bagaimana Anda dapat menghasilkan sesuatu dari sesuatu yang lain. Lihat en.wikipedia.org/wiki/Production_%28computer_science%29 Jadi command : simple_command | compound_command | compound_command redirect_list | function_definition ;adalah produksi yang mengatakan di mana Anda dapat memiliki perintah, itu bisa berupa perintah sederhana, perintah majemuk, atau perintah gabungan dengan pengalihan, atau definisi fungsi.
muru

Jawaban:

6

Itu adalah batasan cara shell memecah garis menjadi token.

Shell membaca baris dari file input dan Menurut bagian 2 "Shell Introduction" mengonversinya menjadi kata atau operator :

  1. Shell memecah input menjadi token: kata dan operator

{Adalah kata yang dilindungi undang-undang

Beberapa kata adalah kata yang dipesan

Kata-kata yang dicadangkan adalah kata-kata yang memiliki arti khusus bagi shell. Kata-kata berikut harus diakui sebagai kata-kata yang dicadangkan:

! { } case do done elif else esac fi for if in then until while

Kata-kata, untuk dikenali sebagai kata-kata, harus dibatasi .

Kata-kata yang dilindungi hanya dikenali ketika dibatasi ...

Sebagian besar dengan titik kosong (poin 7) dan oleh operator.

  1. Jika karakter saat ini adalah <blank> tanpa tanda kutip, token yang mengandung karakter sebelumnya dibatasi dan karakter saat ini harus dibuang.

(adalah operator

Operator berdiri sendiri :

sedangkan operator itu sendiri pembatas.

Di mana "operator" berada :

3.260 Operator

Dalam bahasa perintah shell, operator kontrol atau operator redirection .

Operator pengalihan adalah :

Operator Pengalihan

Dalam bahasa perintah shell, token yang melakukan fungsi pengalihan. Ini adalah salah satu dari simbol berikut:

<     >     >|     <<     >>     <&     >&     <<-     <>

Operator kontrol adalah :

3.113 Kontrol Operator

Dalam bahasa perintah shell, token yang melakukan fungsi kontrol. Ini adalah salah satu dari simbol berikut:

&   &&   (   )   ;   ;;   newline   |   ||

Kesimpulan

Jadi, '(' dan ')' adalah operator kontrol sementara '{' '}' adalah kata-kata yang dicadangkan.

Dan deskripsi yang sama persis dari pertanyaan Anda ada di dalam spec :

Misalnya, '(' dan ')' adalah operator kontrol, sehingga tidak diperlukan <spasi> dalam (daftar). Namun, '{' dan '}' adalah kata-kata yang dicadangkan dalam {list;}, sehingga dalam hal ini diperlukan <spasi> dan <semikolon>.

Yang persis menjelaskan mengapa spasi (atau pembatas lain) diperlukan setelah a {.

Ini valid:

{ echo yes;}

Seperti ini:

{(echo yes);}

Ini:

{(echo yes)}

Atau bahkan ini:

{>/dev/tty echo yes;}
Ishak
sumber
Nah, kutipan terakhir tepat tepat! Diberi +1 Saya perlu meninjau pertanyaan dan jawabannya sekarang
Sergiy Kolodyazhnyy
13

Perbedaan antara kurung kurawal dan kurung adalah bahwa kawat gigi (dan !) adalah kata-kata reserved, seperti for, if, thendll sementara kurung adalah operator control. Kata-kata perlu dipisahkan oleh spasi putih.

Ini berarti sama seperti Anda tidak bisa memilikinya

foriin*; do

kamu tidak bisa

{somecommand;} >file

atau

if !somecommand; then

Spasi yang ditampilkan dalam tata bahasa POSIX bukan spasi yang perlu ada di dalam data input shell, tetapi hanya cara menampilkan tata bahasa itu sendiri. Itu adalah fakta bahwa kurung kurawal adalah kata - kata yang dicadangkan yang menyiratkan bahwa mereka harus dikelilingi oleh spasi, sementara kurung dari sebuah subkulit tidak.

Kusalananda
sumber
1
Yah, ini sepertinya menjawabnya dan saya melihatnya mengatakan "Secara khusus, representasi termasuk spasi antara token di beberapa tempat di mana <blank> tidak diperlukan (ketika salah satu token adalah operator)". Hanya satu pertanyaan: di mana standar didefinisikan (sebagai operator? Itu tidak ada di bagian tata bahasa setidaknya
Sergiy Kolodyazhnyy
@MichaelHomer Ah, "operator kontrol", sama seperti ;. Terima kasih untuk itu.
Kusalananda
Operator kontrol terdaftar di bagian atas halaman manual di bawah DEFINISI. Kita mungkin melihat ()sebagai operator kontrol seperti |yang keduanya melibatkan subkulit. Dan { }bekerja di shell saat ini dan tidak dapat melibatkan subkulit.
glenn jackman
@ Kusalananda Menemukannya, bagian 2.9.2: "Jika pipa dimulai dengan kata yang dipesan! Dan perintah1 adalah perintah subkulit, aplikasi harus memastikan bahwa (operator pada awal perintah1 dipisahkan dari! Oleh satu atau lebih < blank> karakter. Perilaku kata yang dipesan! segera diikuti oleh (operator tidak ditentukan. "Bukan definisi yang jelas tetapi standar menyebutnya (operator
Sergiy Kolodyazhnyy
@ glennjackman Meskipun memang benar bahwa pipa melibatkan subshell, itu bukan jenis definisi yang tampaknya tepat. Standar ini juga menyebutkan bahwa dalam beberapa implementasi tidak masalah bagi pipeline untuk berjalan di lingkungan eksekusi shell saat ini (dan saya tahu itu dalam standar, karena saya melihat teks kemarin dan mencarinya sekarang). Namun, saran Anda mengarahkan saya untuk menemukan kutipan yang saya komentari di atas, di mana paling tidak standar menyebutnya operator meskipun tidak secara eksplisit mendefinisikannya sebagai satu
Sergiy Kolodyazhnyy