Boru önceliği (|) ve mantıksal ve (&&) bash


17

Operatör Önceliği ile klasik senaryo, şöyle bir çizginiz var:

(cd ~/screenshots/ && ls screenshot* | head -n 5)

Ayrıştırılmış mı ((A && B) | C)yoksa (A && B | C)...

Neredeyse resmi belgeler bulundu burada ben sadece tabloda kontrol edemez böylece listede boruyu listelemiyor.

Ayrıca bash, (sadece işlemlerin sırasını değiştirmek için değil , bir alt kabuk oluşturur , bu nedenle bu satırların önceki satırın eşdeğeri olduğundan% 100 emin değilim:

((cd ~/screenshots/ && ls screenshot*) | head -n 5)

Daha genel olarak, bir bash hattının AST'si nasıl bilinir? Python'da, işlem sırasını kolayca iki kez kontrol edebilmem için bana ağacı veren bir fonksiyonum var.


1
Bunun |sadece LHS stdoutuna RHS stdinine uyan bir konektör olduğunu bilmek yardımcı olabilir . Dolayısıyla cd, örneğinizdeki komut başarısız olursa, hiçbir çıktı göndermez head, ancak headyine executede hiçbir şeyi ayrıştırmaz ve çıktı döndürmez.
DopeGhoti


1
bashgeçici bir şey değil yacc ayrıştırıcı kullanıyor ; Eğer aracılığıyla o çalıştırırsanız yacc -vo size verecektir y.outputgüzel bir gramer gösterileri o &&ve ||listelerini birleştirerek, ve listeler sonunda (ters değil) boru hatları oluşur; tl; dr; beklendiği gibi A && B | Caynıdır A && { B | C; }. Arasındaki yürütme herhangi sırasını düşünmeyin Bve C; bir boru hattındaki komutlar paralel olarak çalıştırılır .
Mosvy

1
İşaret ettiğiniz "neredeyse resmi belgelerin" tamamen ilgisiz olduğuna dikkat edin, çünkü [...]testlerde ve $((...))aritmetik değerlendirmelerde kullanılan operatörlerle ilgilidir ; özellikle ||ve &&kabuk dilindeki komutlar listesiyle kullanıldığı gibi , aritmetik değerlendirmedeki veya aritmetik değerlendirmedeki ( daha sıkı bağlandığında ) ilgili operatörlerin aksine aynı önceliğe sahiptir . C&&||
mosvy

@mosvy, bu belge tablonun hangi bağlamda uygulandığını bile söylemiyor, bu yüzden de bu anlamda daha az kullanışlı görünüyor ...
ilkkachu

Yanıtlar:


21
cd ~/screenshots/ && ls screenshot* | head -n 5

Bu şuna eşdeğerdir:

cd ~/screenshots && { ls screenshot* | head -n 5 ; }

( parantez grubu, alt kabuk olmadan birlikte komut verir ). Öncelik |böylece daha yüksek (bağlar sıkı) daha &&ve ||. Yani,

A && B | C

ve

A || B | C

her zaman C'ye sadece B çıktısının verileceği anlamına gelir . Sen kullanabilirsiniz (...)veya { ... ; }anlam ayrımı gerekirse için tek bir varlık olarak birlikte komutları katılmak:

{ A && B ; } | C
A && { B | C ; } # This is the default, but you might sometimes want to be explicit

Bazı farklı komutları kullanarak bunu test edebilirsiniz. Eğer koşarsan

echo hello && echo world | tr a-z A-Z

o zaman alacaksın

hello
WORLD

geri: tr a-z A-Zbüyükecho world harflerle girdi echo hellove kendi başına geçerken , sadece içine pipete olduğunu görebilirsiniz .


Bu edilir tanımlanan kabuk gramer : her ne kadar son derece açık bir şekilde, and_or(için üretim &&/ ||aa sahip olarak tanımlanmıştır) pipelineise, kendi vücudunda pipelinehemen içerir commandki, etmez içeren and_ortek - complete_commandüretim ulaşabilir and_or, ve sadece de var üst düzey ve fonksiyonlar ve döngüler gibi yapısal yapıların gövdeleri içinde.

Komut için ayrıştırma ağacı almak üzere bu dilbilgisini el ile uygulayabilirsiniz, ancak Bash hiçbir şey sağlamaz. Kendi ayrıştırmalarında kullanılanın ötesinde bir kabuk bilmiyorum.

Kabuk dilbilgisinin sadece yarı-biçimsel olarak tanımlanmış birçok özel durumu vardır ve bu doğru bir görev olabilir. Bash bile bazen yanlış anladı , bu yüzden pratiklikler ve ideal farklı olabilir.

Sözdizimini eşleştirmeye ve bir ağaç üretmeye çalışan dış ayrıştırıcılar var ve bunlardan en çok güvenilir olmaya çalışan Morbig'i tavsiye edeceğim .


7

TL; DR : gibi ayırıcıları listeler ;. &,, &&ve ||ayrıştırma sırasına karar verin.

Bash kılavuzu söyler:

AND ve OR listeleri , && ve || ile ayrılmış bir veya daha fazla boru hattının dizisidir. kontrol operatörleri.

Veya Bash Hacker'ın wiki'si nasıl kısaca koydu

<PIPELINE1> && <PIPELINE2>

Böylece, cd ~/screenshots/ && ls screenshot* | head -n 5 bir boru hattı ls screenshot* | head -n 5ve bir basit komut vardır cd ~/screenshots/. El kitabına göre

Bir boru hattındaki her komut ayrı bir işlem olarak yürütülür (yani, alt kabukta).

Öte yandan, (cd ~/screenshots/ && ls screenshot*) | head -n 5farklı - bir boru hattınız var: solda alt kabuk var ve sağda var head -n 5. Bu durumda OP'nin gösterimini kullanarak(A && B) | C


Bir örnek daha alalım:

$ echo foo | false &&  echo 123 | tr 2 5
$

Burada bir listemiz var <pipeline1> && <pipeline2>. Boru hattının çıkış durumunun son komutla aynı olduğunu ve falsenegatif durum olarak da başarısız olduğunu bildiğimiz için , &&sağ tarafı yürütmez.

$ echo foo | true &&  echo 123 | tr 2 5
153

Burada sol boru hattı başarı çıkış durumuna sahiptir, bu nedenle sağ boru hattı yürütülür ve çıktısını görürüz.


Kabuk dilbilgisinin gerçek yürütme sırası anlamına gelmediğini unutmayın. Gilles'in cevabından birini alıntılamak :

Borulu komutlar aynı anda çalışır. Ps çalıştırdığınızda | grep…, ps veya grep'in önce başlayıp başlamamasıyla ilgili olarak çekiliş şansı (veya kabuğun işleyişinin ayrıntılarının bir meselesi, çekirdeğin bağırsaklarının derinliklerinde ince ayarlayıcı ile birlikte) ve her durumda devam ediyor aynı anda yürütmek.

Ve bash kılavuzundan:

AND ve OR listeleri sol ilişkilendirme ile yürütülür.

O dayanarak , ilk idam edileceğini önceki komut başarılı olursa, ancak bir ilk işlem ziyade kökenli olabilir onlar bir boru hattı bulunmaktadır beri.cd ~/screenshots/ && ls screenshot* | head -n 5cd ~/screenshots/ls screenshot* | head -n 5head -n 5ls


1
Sorunun, hangi şeylerin ortaya çıktığı hakkında bir şey sorduğunu bilmiyorum.
Michael Homer

"Hangisinin önce ortayacd ~/screenshots/ && ls screenshot*head -n 5 çıktığı gibi bir öncelik yoktur ya da " Peki, evet, durum böyle ((cd ~/screenshots/ && ls screenshot*) | head -n 5). Ancak cd ~/screenshots/ && ls screenshot* | head -n 5, meselenin noktası gibi görünen belirsiz vaka hakkında bir şey söylemez (çevreleyen parantez ile veya parantez olmadan).
ilkkachu

@ilkkachu Doğru, ama aşağıdaki cümleler buna değiniyor. cd ~/screenshots/ && ls screenshot* çünkü ilk olarak işlenmesi gerekir &&listeleri öncelik sırasına daha üsttedir (l0b0 en Yanıta en azından alınır). Cevabı nerede geliştirmem gerektiğini düşünüyorsun?
Sergiy Kolodyazhnyy

@SergiyKolodyazhnyy, sorunun her ikisine de sahip olduğu (cd && ls | head)ve ((cd && ls) | head)hangisini kastettiğiniz konusunda açık olmak iyi olabilir.
ilkkachu

@ilkkachu Tamam, şimdilik bunu sileceğim ve bu arada düzenleyeceğim
Sergiy Kolodyazhnyy

3

Burada belirtildiği yer bash(1):

SHELL GRAMMAR
[...]
   Pipelines
       A  pipeline  is  a sequence of one or more commands separated by one of
       the control operators | or |&.
[...]
   Lists
       A list is a sequence of one or more pipelines separated by one  of  the
       operators ;, &, &&, or ||, and optionally terminated by one of ;, &, or
       <newline>.

Böylece, &&boru hatlarını ayırır.


2

Sadece deneyebilirsin echo hello && echo world | less. Bunun |daha yüksek önceliğe sahip olduğunu göreceksiniz (Bir komut satırı, bir komuttur). 2. örneğiniz için orada aynı DEĞİLDİR . Ancak cdçıktısı olmadığı için hiçbir fark göremezsiniz, eter yolu.

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.