Neden sh döngülerinde "do" dan sonra ";" yok?


28

Neden tek bir satıra yazıldığında kabuk döngülerinden ;sonra bir karakter yok do?

İşte demek istediğim. Birden çok satıra yazıldığında, fordöngü şöyle görünür:

$ for i in $(jot 2)
> do
>     echo $i
> done

Ve tek bir hatta:

$ for i in $(jot 2); do echo $i; done

Daraltılmış tüm çizgiler , satır dışında; onlardan sonra bir satır alır ve eğer eklerseniz , bu bir hatadır. Muhtemelen benden çok daha zeki biri, bunun bir sebeple yapılacak doğru şey olduğuna karar verdi, ama nedeninin ne olduğunu çözemiyorum. Bana tutarsız görünüyor.do;

whileDöngülerle de aynı şey .

$ while something
> do
>     anotherthing
> done
$ while something; do anotherthing; done


2
Noktalı virgül sonrası vardır: O tutarlıdır while/ forya.
Dmitry Grigoryev

Hemen akla gelen şey, sadece gerekli olmadığıdır. Başka yerlerde, noktalı virgüller ifadeleri birbirinden ayırır.
Paul Draper

Çünkü gereksiz olurdu. Onsuz belirsizlik yoktur.
user207421

Yanıtlar:


29

Bu komutun sözdizimidir. Bileşik Komutlarına Bakın

for name [ [in [words …] ] ; ] do commands; done

Özel olarak not edin: do commands

Çoğu insan koymak dove commandsayrı bir satıra daha kolay okunabilmesi için izin vermek ancak gerekli değildir, yazabilirsiniz:

for i in thing
do something
done

Bu sorunun özellikle kabukla ilgili olduğunu biliyorum ve bash el kitabına bağladım. Kabuk kılavuzunda bu şekilde yazılmamıştır, ancak bu şekilde byte dergisi için Stephen Bourne tarafından yazılmış bir makalede yazılmıştır .

Stephen diyor ki:

Bir komut listesi , bir yeni satır veya ;(noktalı virgül) ile ayrılmış veya sonlandırılmış bir veya daha fazla basit komutun bir dizisidir . Ayrıca, gibi kelimeleri saklıdır do ve bitmiş normalde bir satır öncesinde veya edilir ;... aşağıdaki komutu listesi her zaman çevirmek do yürütülür.


5
Bunun gibi bir noktalı virgül olmaması gerektiğini de ilginç olurdu for i in thing; do; something; done. Satır kesmesine izin verilmesine rağmen, noktalı virgül kullanılamaz.
rexkogitans

@gidds: evet, kesinlikle. Kabuk dilbilgisi de bu şekilde yapılandırılmıştır. somethingTabidir ve dobunun için de geçerlidir. Tıpkı İngilizce cümle yapısındaki gibi.
Peter Cordes

@gidds Bir hazır bilgi (veya başka bir sözdizimi parçası) gereklidir, çünkü birden çok komut koşulda ( whilesözdiziminde) yer alabilir, bu nedenle koşul komutlarını döngü vücut komutlarından farklılaştırmak için bir şeye ihtiyacınız vardır. doOnları ayırmak için kullanmak muhtemelen en uygun görünen şeydi.
JoL

@rexkogitans Gerçekten, bunun bir sözdizimi hatası olduğunu asla anlamadım. Bu başlık sorusu da bunun için çok uygun. Muhtemelen boş bir vücuda izin vermeyerek yapmak zorundadır. Olsa da, yeni bir satır ile boş bir gövde yaparken biraz farklı bir sözdizimi hatası alırsınız ve örneğin boş bir gövdesi yoktur.
JoL

@rexkogitans Buradaki noktalı virgül, döngü sözdiziminin bir parçasıdır ve komut listesi sonlandırıcısı olarak diğer rolünden farklıdır. Newline farklıdır, çünkü aksi takdirde istenmiyorsa veya beklenmiyorsa normal boşluklar gibi işlem görür. Kabuk dilbilgisi dağınık.
chepner

12

Bu sözdiziminin asıl nedeninin ne olduğunu bilmiyorum, ama whiledöngülerin koşul bölümünde birden fazla komut alabileceğini düşünelim.

while a=$(somecmd);
      [ -n "$a" ];
do
    echo "$a"
done

Burada, doanahtar kelimenin koşul bölümünü ve döngünün ana gövdesini ayırmak için gereklidir. doAnahtar gibidir while, ifve then(ve done) ve kendinden sonra noktalı virgül veya satır başı karakteri gerektirir ama bir komutla hemen önce görünür olmadığı başkaları ile uyumlu görünmektedir.

Alternatif (genelleştirilmiş ifve while) biraz çirkin görünür, örneğin yazmamız gerekirdi.

if; [ -n "$a" ]; then
    some command here
fi

forDöngülerin sözdizimi sadece benzer.


11

Kabuk sözdizimi önek tabanlıdır. Özel anahtar kelimeler tarafından tanıtılan cümlecikleri vardır. Bazı maddeler birlikte gitmeli.

Bir whiledöngü bir veya daha fazla test komutundan oluşur:

test ; test ; test ; ...

ve bir veya daha fazla vücut komutuyla:

body ; body ; body ; ...

Bir şey kabuğa bir süre döngüsünün başladığını söylemek zorunda. whileKelimenin amacı budur :

while test ; test ; test ; ...

Ama sonra, işler belirsizdir. Bedenin başlangıcı hangi komuttur? Bir şey bunu belirtmek zorundadır, ve doönek böyle yapar:

do body ; body ; body ; ...

ve son olarak, bir şey son vücudun görüldüğünü belirtmek zorundadır; özel bir anahtar kelime donebunu yapar.

Bu kabuk anahtar kelimeler, aynı satırda bile noktalı virgül ayırma gerektirmez. Örneğin, birkaç iç içe döngüyü kapatırsanız, sadece sahip olabilirsiniz done done done ....

Aksine, noktalı virgül aynı satırdalarsa arasındadır ... test ; body ... . Bu noktalı bir sonlandırıcı olduğu anlaşılmaktadır: Birlikte ait test. Bu nedenle, bunlar doarasına bir anahtar kelime girilmişse, noktalı virgül ile body. Noktalı virgülün diğer tarafında olsaydı test, komutlar arasına yerleştirilmek yerine yanlış bir şekilde komutun sözdiziminin içine gömülürdü.

Kabuk sözdizimi aslen Stephen Bourne tarafından tasarlandı ve Algol'dan ilham aldı . Bourne Algol'ü o kadar çok severdi ki, C'nin Algol gibi görünmesi için kabuk kaynak kodunda birçok C makrosu kullandı. Sen edebilirsiniz Versiyon 7 Unix'den 1979-tarihli kabuk kaynakları taramak . Makrolar içeridedir mac.hve her yerde kullanılırlar. Örneğin ififadeler IF... ELSE... ELIF... olarak işlenir FI.


Kaynak kodu etkileyici.
keithpjolley

Evet, bir tur cpp.
stolenmoment

7

Bunun doburada özel olmadığını iddia ediyorum . Hata alırsınız, çünkü ;komut listesi başlatılamıyor. Öyle olsaydı, ilk komut boş olurdu ve dilbilgisi boş komutlara izin vermez (komut olmadan değişken atamaları ya da yönlendirmeler, evet, ama kesinlikle hiçbir şey, hayır). Bu, bir komut listesinin beklendiği yerlerde, herhangi bir sayıda yerde geçerlidir:

$ while true; do ; echo foo; done
dash: 1: Syntax error: ";" unexpected
$ while ; true; do; echo; done
dash: 1: Syntax error: ";" unexpected
$ { ; echo foo; }
dash: 1: Syntax error: ";" unexpected
$ if ; true; then echo foo; fi
dash: 1: Syntax error: ";" unexpected

Üstelik:

$ ; ;
dash: 1: Syntax error: ";" unexpected

Tüm bu yerlerde, bir komut listesi bekleniyor ve bu nedenle bir lider ;beklenmiyor.


Evet - 'do' işleminden sonra '' n '' dizisini keyfi bir şekilde eklediğim yol, 'do' işleminin tek başına belirteç olduğunu ve izleyen blokta işlenen bir şey olmadığını düşünmemi sağladı.
keithpjolley

Kaçış olmayan bir yeni çizgiye (aksi halde kabuk sözdiziminde noktalı virgül gibi davranıyor gibi görünüyor) nasıl olsa da do(ve ifvb.) İzin verilir ?
Henning Makholm

@Henning Bir komut listesinden önce (ve sonra) herhangi bir sayıda yeni satıra izin verilir. Newlines ve noktalı virgüller de diğer yönlerden farklı davranır. Örneğin, takma adın genişletilmesi, bir girdi satırının tamamı okunduğunda (yani bir sonraki yeni satıra kadar) yapılır ve komut başına değil.
muru,

3

Sözdizimi:

for i in [whitespace separated list of values]
do [newline separated list of commands]
done

Yeni satırlardan herhangi biri, komut listesinde veya "do" veya "done" dan önce, ";" ile değiştirilebilir.

"Yap" dan ve "in" den önce, sadece işlerin daha güzel görünmesi için yeni bir satıra (ancak ";" değil) izin verilir , ancak orada yeni bir satır olması gerekmez .


3

if Anahtar kelimelerine benzer: komutlar kısa olduğunda bu oldukça okunabilir:

if   test_commands
then true_commands
else false_commands
fi

Ben keyfi koyarak fark etti sonra \nsonra do(yaklaşık sanmıyorum uzun olduğunca o şey anlam kazandı değil keyfi koymak edememek \ndiğer komutlar ve args arasında).
keithpjolley

Eh, do, then, elsedeğil args - onlar olsaydı, onlardan önce noktalı virgül kullanmasına izin verilmez. Onlar kabuk anahtar kelimelerdir (bkz. type if then elif else fi)
glenn jackman

Sanırım cevabımda olmak istediğim kadar net değildim.
keithpjolley

Demek istediğim, "yapmak" herhangi bir "diğer komut" gibi değildir. Bu yüzden farklı kurallara uyar.
glenn jackman

3

Kısa cevap, çünkü POSIX kabuk dilbilgisi tarafından belirtilmiş . Ardışık ayırıcı olsa da , bir grup ifadenin arasında dove arasında herhangi bir şey donekabul edilir ;:

for_clause       : For name                                      do_group
                 | For name                       sequential_sep do_group
                 | For name linebreak in          sequential_sep do_group
                 | For name linebreak in wordlist sequential_sep do_group

do_group         : Do compound_list Done 

sequential_sep   : ';' linebreak
                 | newline_list

Ek olarak, eğer ;gerekliyse, standart açıkça ifade edecekti ve sequential_sepsonradan da içerecekti Do.


1
@ drewbenn İlkini mi kastediyorsun? Bu pozisyonel parametrelerle yineleniyor. Öyleyse ./myscript.sh abc adında bir betiğiniz varsa, burada abc argümandır, i; yankı yapmak "$ i"; hala çalışmak için noktalı virgül ihtiyacı olacağını düşünüyorum olsa da, abc üzerinden döngü olurdu
Sergiy Kolodyazhnyy

Tamam, şüphelerim de temizlendi
Sergiy Kolodyazhnyy

1

Çünkü do bir anahtar kelimedir ve onu takip eden temelde parametrelerdir. Bash tercümanı daha fazlasını takip ettiğini biliyor. Olmadığı gibi; ';' for komutunda i'yi izleyerek. Aslında i'den sonra yeni bir satır ekleyebilir ve gerisini yeni bir satıra yazabilirsiniz.

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.