POSIX, burada komut değiştirme içindeki alıntılanmış belgeler için ne gerektirir?


20

Gelen bu soru birisi bir kullanırken sorun raporları burada belgeyi içinde bir alıntı sınırlayıcı kelime ile $(...)komut ikamesi bir ters eğik çizgi, \belge tetikleyiciler içinde bir satırın sonundaki newline-birleştiren çizgi devamında , burada aynı süre belgelemek dışında beklendiği gibi komut ikamesi işleri .

İşte basitleştirilmiş bir örnek belge:

cat <<'EOT'
abc ` def
ghi \
jkl
EOT

Bu, bir satırın sonunda bir ters tırnak ve bir ters eğik çizgi içerir. Sınırlayıcı belirtilir, bu nedenle vücudun içinde herhangi bir genişleme meydana gelmez. Tüm Bourne-aliklerinde bu çıktıları kelimesi kelimesine bulabilirim. Aynı belgeyi aşağıdaki gibi bir komut yerine koyarsam:

x=$(cat <<'EOT'
abc ` def
ghi \
jkl
EOT
)
echo "$x"

artık aynı şekilde davranmazlar:

  • dash, ash, zsh, ksh93, BusyBox ash, mkshve SunOS 5.10 POSIX shhepsi daha önce olduğu gibi dökümanının birebir içeriğini verir.
  • Bash 3.2, benzersiz bir backtick için bir sözdizimi hatası verir. Eşleştirilen ters tırnaklarla, içeriği bir komut olarak çalıştırmaya çalışır.
  • Bash 4.3, "ghi" ve "jkl" değerlerini tek bir satıra daraltır, ancak hata içermez. --posixSeçenek bu etkilemez. Kusalananda bana pdkshaynı şekilde davrandığını söylüyor (teşekkürler!) .

Orijinal soruda, bunun Bash ayrıştırıcısında bir hata olduğunu söyledim. Bu mu? [Güncelleme: evet ] Bulabileceğim POSIX'ten (tümü Kabuk Komut Dili tanımından) ilgili metin:

  • §2.6.3 Komut Değiştirme :

    $ (Komut) formuyla, eşleşen kapanış parantezine açık parantezin ardından gelen tüm karakterler komutu oluşturur. Herhangi geçerli kabuk komut dosyası için kullanılabilir komutu yalnızca belirtilmemiş sonuçlar üretir yönlendirmeler oluşan bir senaryo dışında.

  • §2.7.4 Burada-Belge :

    Herhangi bir bölümü ise kelimenin alıntı, ayırıcı üzerindeki alıntı çıkarılmasını gerçekleştirerek kurulacaktır kelime ve burada-belge satırları, genişletilmiş edilmeyecektir.

  • §2.2.1 Kaçış Karakteri (Ters Eğik Çizgi) :

    <newline> <ters eğik çizgiyi> takip ederse, kabuk bunu satır devamı olarak yorumlayacaktır. Giriş, belirteçlere bölünmeden önce <ters eğik çizgi> ve <yeni satır> kaldırılacaktır.

  • §2.3 Jeton Tanıma :

    Bir io_here belirteci dilbilgisi tarafından tanındığında (bkz. Kabuk Dilbilgisi ), bir sonraki NEWLINE belirtecinin hemen ardından gelen bir veya daha fazla satır , bir veya daha fazla burada bulunan belgenin gövdesini oluşturur ve Here- kurallarına göre ayrıştırılır. Belge .

    Bir io_burayı işlemediğinde , kabuk, girişindeki bir sonraki karaktere aşağıdaki ilk uygulanabilir kuralı uygulayarak girdisini belirteçlere bölmelidir . ...

    ...

    1. Geçerli karakter <ters eğik çizgi>, tek tırnak veya çift tırnak işareti içeriyorsa ve tırnak içine alınmamışsa, tırnak içine alınan metnin sonuna kadar sonraki karakterler için tırnak işaretini etkiler. Alıntı için kurallar açıklanmaktadır teklif . Jeton tanıma sırasında hiçbir ikame gerçekleştirilmeyecek ve sonuç belirteci, girişte görünen (<newline> katılma hariç), değiştirilmemiş, gömülü veya ekli tırnak işaretleri veya ikame operatörleri dahil olmak üzere, ve son arasındaki karakterleri içermelidir. alıntılanan metnin.

Benim yorumum $(, sonlandırmaya kadar olan tüm karakterlerin )kabuk betiğini, kelimesi kelimesine; burada belge görünür, bu nedenle sıradan belirleme yerine burada belge işleme gerçekleşir; buradaki belgenin alıntılanmış bir sınırlayıcısı vardır, yani içeriği kelimesi kelimesine işlenir; ve kaçış karakteri asla içine girmez. Ancak bu durumun ele alınmadığına ve her iki davranışa da izin verildiğine dair bir argüman görebiliyorum. Bir yerde de alakalı metnin bazılarını atlamış olabilirim.


  • Bu durum başka yerlerde daha açık hale getirildi mi?
  • Taşınabilir bir script neye güvenebilmelidir (teoride)?
  • Bu kabuklardan herhangi birinin (Bash 3.2 / Bash 4.3 / diğer herkes) verdiği özel tedavi standart tarafından zorunlu mu? Yasak? İzin verilen?

Bize ikinci durumda üretiminizi nasıl ürettiğinizi gösterebilir misiniz?
Julie Pelletier

@JuliePelletier echo "$x", ancak değişken çalışmalarını incelemek için herhangi bir yol. O satırı dibine düzenledim.
Michael Homer

2
Bu kolay bir düzeltme gibi görünüyor. Bu yama en azından işe yarıyor gibi görünüyor: ignore_quoted_newline_in_quoted_heredoc.patch
geirha

1
Bunu doğru yorumladığınızı ve imo standart oldukça açık olduğunu düşünüyorum çünkü "Kabuk bir subshell ortamında [...] komutunu çalıştırarak ve yerine [...] komutunun standart çıktı komutu [...] " Bu yüzden komutu bir alt kabukta çalıştırır ve $(...)bu çıktı ne olursa olsun onun yerine geçer ... Şimdi, örneğin bir alt kabukta (in bash) komutu çalıştırdığınızda beklenen sonucu verir. Yalnızca komut yerine koymaya dönüştürüldüğünde "ghi" ve "jkl" kelimelerini daraltır. Yani bu bir böcek imo
don_crissti

2
@geirha Bir Bash hatası rapor ettim ; Mevcut bakım gölgesine bile sahip olmadığı için pdksh'i rahatsız etmeyeceğim.
Michael Homer

Yanıtlar:


5

Bu Bash'ın posta listesinde soruldu ve destekçi bunun bir hata olduğunu onayladı

POSIX'teki metnin "belirsiz olması gerekmediğini, ancak yakın okuma gerektirdiğini" de belirtmişlerdir. Bu yüzden bununla ilgili açıklama istedim. Sorunun bir açıklaması ve standardın yorumlanması da dahil olmak üzere cevapları şöyleydi:

Komut ikamesi kırmızı bir ringa balığıdır; yalnızca hatanın nerede olduğunu belirtmesi açısından önemlidir.

Bu belgedeki sınırlayıcı alıntılanmıştır, bu nedenle çizgiler genişletilmez. Bu durumda kabuk, satırdan girdi olarak satırları alıntılanmış gibi okur. Bir ters eğik çizgi, alıntılandığı bir bağlamda görünürse, bir kaçış karakteri gibi davranmaz (aşağıya bakın) ve ters eğik çizgi-yeni satırının özel işlenmesi gerçekleşmez. Aslında, sınırlayıcının herhangi bir kısmı alıntılanırsa, buradaki belge satırları tek tırnaklı gibi okunur.

Posix 2.2.1'deki metin garip bir şekilde yazılmıştır, ancak ters eğik çizginin yalnızca alıntılanmadığında özel olarak ele alındığı anlamına gelir. Bir ters eğik çizgi belirtebilir ve tüm genişlemeyi yalnızca tek tırnak veya başka bir ters eğik çizgi ile engelleyebilirsiniz.

Yakın okuma kısmı, tek tırnakları ifade eden "genişlememiş" metindir. Standart, 2.2'de, belgelerin "başka bir alıntı biçimi" olduğunu, ancak kelimelerin hiç genişletilmediğinin tek alıntı biçiminin tek tırnak olduğunu söylüyor. Yani bu, tek tırnaklar gibi değil, tek tırnaklar gibidir.


@Scott (1) Bunun tüm soruları yanıtladığına inanıyorum ve hiçbir şey gereksiz değil. Cevabı başlatan yorumum, durumu yanlış anlayan bir moderatör tarafından yapılan silme ile ilgili. (2) Yeteri kadar itibarım yok. (3) Yanıtlarımı silenler tarafından benzer davranışları takdir ederdim, ancak gelecekte bunu kesinlikle aklımızda tutacağım. Düşünceleriniz için teşekkürler.
Kevin

Demek istediğim, ilk paragrafınızın çoğunun, sorunun cevabı değil, Michael Mrozek ile bir konuşma olmasıydı. Herhangi bir yayına yorum yapmak için yeterli üne sahip olmadığınızın farkındayım, ancak meta ve sohbet için yeterli sayıda olduğuna inanıyorum.
Scott

1
@Scott Cevabı düzene sokmaya çalıştığınızı anlıyorum ve takdir ediyorum, ancak daha önce tam olarak aerodinamik cevabı yayınladım (sadece alıntı ve ona bir bağlantı) ve söz konusu moderatör tarafından (herhangi bir tartışma olmadan) silindi ve ben sohbet etmek ve bu karara itiraz etmek için silinen yayında hiçbir bağlantı görmeyin. Asılsız eleştirisine cevap vererek, silme işleminden kurtulacağını, asker tarafından kabul edileceğini ve ardından önsözü kaldırmak için cevabı değiştireceğimi umdum.
Kevin
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.