Bash ayraç genişletme ve komut gruplama arasında nasıl farklılaşır?


47

{Ayraç genişletmede kullanılabileceğini fark ettim :

echo {1..8}

veya komut gruplarında:

{ls;echo hi}

Bash farkı nereden biliyor?


1
Mükemmel soru, +1. O olabilir gibi görünüyor {, bir komutun başında ve aksi bir bağ genişleme olarak görünse bile bir komut listesi olarak yorumlanır, ama emin değilim.
Celada

16
{ls;echo hi}yasal değildir bash. Açılıştan sonra bir boşluk ve kapanmadan önce bir noktalı virgül gerekir.
PSkocik

Yanıtlar:


38

Basitleştirilmiş bir nedeni bir karakter varlığıdır: space.

Parantez açılımları (kote olmayan) boşlukları işlemez.

Bir {...}liste (alıntılanmamış) boşluklar gerektirir.

Daha ayrıntılı cevap, kabuğun bir komut satırını nasıl ayrıştırdığıdır .


Bir komut satırını ayrıştırma (anlama) ilk adımı bölümlere ayırmaktır.
Bu bölümler (genellikle kelimeler veya belirteçler olarak adlandırılır) her meta-karakterdeki bir komut satırını linkten ayırmaktan kaynaklanır :

  1. Komutu, sabit meta-karakter kümesi ile ayrılmış belirteçlere böler: SPACE, TAB, NEWLINE,;, (,), <,>, |, ve &. Simge türleri arasında kelimeler, anahtar kelimeler, G / Ç yönlendiricileri ve noktalı virgül bulunur.

Meta karakterler: spacetabenter;,<>|and &.

Bölünmeden sonra, kelimeler bir tür olabilir (kabuk tarafından anlaşıldığı gibi):

  • Komut ön atamaları: LC=ALL ...
  • komuta LC=ALL echo
  • Argümanlar LC=ALL echo "hello"
  • Yönlendirme LC=ALL echo "hello" >&2

Ayraç genişletme

Yalnızca bir "ayraç dizesi" (boşluklar veya meta karakterler olmadan) tek bir sözcükse (yukarıda açıklandığı gibi) ve alıntılanmadıysa , "Ayraç genişletme" için bir adaydır. Daha sonra iç yapı üzerinde daha fazla kontrol yapılır.

Böylece, bu: ya da (bash'da zsh farklı) {ls,-l}olmak için "Brace genişlemesi" olarak nitelendirilir .ls -lfirst wordargument

$ {ls,-l}            ### executes `ls -l`
$ echo {ls,-l}       ### prints `ls -l`

Ama bu olmaz: {ls ,-l}. Bash bölünür spaceve satırı iki kelimeyle ayrıştırır: {lsve ,-l}hangisini tetikleyecektir command not found(bağımsız değişken ,-l}kaybolur):

 $ {ls ,-l}
 bash: {ls: command not found

Satır: iki meta karakter ve {ls;echo hi}çünkü "Brace genişleme" olmayacak .;space

Bu üç bölüme ayrılacaktır: {lsYeni komutu: echo hi}. ;Yeni bir komutun başladığını tetiklediğini anlayın . Komut {lsbulunmayacak ve bir sonraki komut basılacaktır hi}:

$ {ls;echo hi}
bash: {ls: command not found
hi}

Başka bir komuttan sonra yerleştirilirse, aşağıdakilerden sonra yeni bir komut başlatır ;:

$ echo {ls;echo hi}
{ls
hi}

Liste

"Bileşik komutları" biri "Ayraç Listesi" (sözlerim) 'dir: { list; }.
Gördüğünüz gibi boşluk ve kapanışla tanımlanır ;.
Boşluklar ve ;hem çünkü ihtiyaç vardır {ve }"Ayrılmış olan Kelimeler ".

Ve bu nedenle, kelimeler olarak tanınmak için, meta-karakterlerle çevrili olmak gerekir (hemen hemen her zaman:) space.

Bağlantılı sayfanın 2 noktasında açıklandığı gibi

  1. Her komutun ilk belirteci olup olmadığını kontrol etmek için ...., {, veya () olup olmadığını kontrol eder, sonra komut aslında bir bileşik komuttur.

Örnek: {ls;echo hi}bir liste değil.

Bir kapanma ;ve en az bir kere sonra boşluk gerekir {. Sonuncusu }kapanış tarafından tanımlanır ;.

Bu bir liste { ls;echo hi; }. Ve bu { ls;echo hi;}da (daha az kullanılan, ancak geçerli) (Yardım için teşekkürler @choroba).

$ { ls;echo hi; }
A-list-of-files
hi

Ancak bir komutun argümanı (kabuk farkı bilir), bir hatayı tetikler:

$ echo { ls;echo hi; }
bash: syntax error near unexpected token `}'

Ama kabuğun ayrıştırdığına inandığına dikkat et:

$ echo { ls;echo hi;
{ ls
hi

2
bu gerçekten en iyi cevap, çünkü bize gerçekten ayrıştırıcının nasıl çalıştığını veriyorsunuz! ve ayrıntılı bir açıklama ile!
saat

2
Sen arasında boşluk gerekmez ;ve }. { ls;}noktalı virgül zaten bir meta karakter olduğu için çalışır.
choroba

1
@lovespring Teşekkürler, evet, yazmaya biraz zaman ayırdım. Yararlı olduğunu bilmek beni mutlu ediyor. Tekrar, teşekkürler.

mükemmel makale, referanslar için çok teşekkürler
Edward Torvalds

16

Blok {bir kabuk anahtar sözcüğüdür, bu nedenle bir sonraki kelimeden boşlukla ayrılmalıdır, küme ayracı genişletmede boşluk kalmamalı (boşluk genişletmek gerekirse, kaçmak zorunda kalırsınız:) echo {\ ,a}{b,c}.

Bir komutun başında ayraç genişletme kullanabilirsiniz:

{ls,.}  # expands to "ls ."

Gruplandırma komutlarının ayrıştırılması genişletmelerden önce gerçekleştiğinden, bir bloğa genişletmek için kullanamazsınız:

echo {'{ ls','.;}'}  # { ls .;}
{'{ ls','.;}'}       # bash: { ls: No such file or directory

5

Komut satırının sözdizimini kontrol ederek bilir. Aynı şekilde, ifadede echo echo, ilk yankının bir komut olarak ve ikinci yankının, ilk yankının bir parametresi olarak ele alınması gerektiğini bilir .

Bash'te çok basittir, çünkü { cmd; }boşluk ve noktalı virgül içermelidir. Bununla birlikte, örneğin, zsh'de gerekli değildir, ancak yine de {}kabuk bağlamı analiz edilerek içeriği ile ne yapılması gerektiğini söyleyebilirsiniz.

Aşağıdakileri göz önünde bulundur:

alias 1..3=date
{ 1..3; }    #in bash
{1..3}       #in zsh

Her ikisi de geçerli tarihi döndürür, ancak

echo {1..3}

1 2 3shell {}komutunun argümanında olduğunu bildiğinden döner echo, böylece genişletilmelidir.


{ardından tırnaksız boşluk, bash'ta ayraç genişlemesine başlamaz.
choroba

@choroba Evet, ve hemen sonra {. Tırnaksız alan hiçbir yerde olamaz çünkü kabuk tüm komut satırını boşluklara böler.
jimmij

0

Öncelikle, bir bileşik küme teker teker ve komut satırının ilk sözcüğü olmalıdır:

echo { these braces are just words }

İkincisi, bireysel diş telleri özel değildir (yukarıda gördüğünüz gibi). Boş parantezler de özel değildir:

echo {} # just the token {}: familiar from the find command

Virgülsüz herhangi bir şey aynı zamanda sadece kendisidir

echo {abc} # just {abc}

Aksiyonun başladığı yer burasıdır.

echo {a,b} # braces disappear, a b results.

Dolayısıyla, temel olarak küme genişlemesinin başlayabilmesi için, içinde {...}en az bir virgül bulunan en az bir örneği olduğu tek bir kelimeye (beyaz alandaki alanlara ayrılmamış) ihtiyacımız var.

Bu arada, komut satırındaki ilk sözcük olabilir :

{ls,-l} .   # just "ls -l ."
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.