Kabuk yerleşiği ve kabuk anahtar kelimesi arasındaki fark nedir?

28

Bu iki komutu çalıştırdığımda

alıyorum
$ type cd
cd is a shell builtin
$ type if
if is a shell keyword

Açıkça, cd 'in bir kabuk yerleşimi ve if ' nin bir kabuk anahtar kelimesi olduğu açıkça görülmektedir. Peki, shell yerleşiği ile anahtar kelime arasındaki fark nedir?

    
sordu Avinash Raj 10.04.2014 04:47

3 cevap

39

Bash kodunuzu ayrıştırma biçiminde, bir dahili anahtar ile bir anahtar kelime arasında güçlü bir fark var. Farkdan bahsetmeden önce, tüm anahtar kelimeleri ve yerleşikleri listeleyelim:

Yerleşikleri:

$ compgen -b
.         :         [         alias     bg        bind      break     
builtin   caller    cd        command   compgen   complete  compopt   
continue  declare   dirs      disown    echo      enable    eval      
exec      exit      export    false     fc        fg        getopts   
hash      help      history   jobs      kill      let       local     
logout    mapfile   popd      printf    pushd     pwd       read      
readarray readonly  return    set       shift     shopt     source    
suspend   test      times     trap      true      type      typeset   
ulimit    umask     unalias   unset     wait                          

Anahtar Kelimeler:

$ compgen -k
if        then      else      elif      fi        case      
esac      for       select    while     until     do        
done      in        function  time      {         }         
!         [[        ]]        coproc              

Örneğin, [ öğesinin yerleşik olduğunu ve [[ 'nin bir anahtar kelime olduğunu unutmayın. Bu farkı, iyi bilinen operatörler olduklarından, aşağıdaki farkı gösterecek şekilde kullanacağım: herkes bunları biliyor ve düzenli olarak kullanıyor (veya yapmalı).

Bir anahtar kelime Bash tarafından ayrıştırılmakta çok erken bir zamanda taranır ve anlaşılır. Bu, örneğin aşağıdakilere izin verir:

string_with_spaces='some spaces here'
if [[ -n $string_with_spaces ]]; then
    echo "The string is non-empty"
fi

Bu iyi çalışıyor ve Bash mutlu bir şekilde çıkacak

The string is non-empty

$string_with_spaces alıntı yapmadığımı unutmayın. Oysa şu:

string_with_spaces='some spaces here'
if [ -n $string_with_spaces ]; then
    echo "The string is non-empty"
fi

, Bash'in mutlu olmadığını gösterir:

bash: [: too many arguments

Neden dahili anahtarlarla değil, anahtar kelimelerle çalışır? Bash kodu ayrıştırdığı zaman, anahtar kelime olan [[ değerini görür ve bunun çok özel olduğunu anlar. Böylece ]] kapanışını arayacak ve içeriye özel bir şekilde davranacaktır. Bir yerleşik (veya komut) argümanlarla çağrılacak gerçek bir komut olarak kabul edilir. Bu son örnekte, bash [ komutunu argümanlarla çalıştırması gerektiğini (satır başına bir tane gösterilmiştir):

-n
some
spaces
here
]

Değişken genişleme, alıntı kaldırma, yol adı genişletme ve kelime bölme gerçekleştiği için. % Co_de% komutunun kabukta oluşturulduğu ortaya çıkar, dolayısıyla bu argümanlar ile yürütülür, bu da bir hatayla sonuçlanır, dolayısıyla şikayetle sonuçlanır.

Pratikte, bu ayrımın karmaşık davranışlara izin verdiğini görüyorsunuz; bu, yerleşiklerle (veya komutlarla) mümkün olmayacaktır.

Yine de pratikte, bir yerleşimi bir anahtar kelimeden nasıl ayırt edebilirsiniz? Bu gerçekleştirmek için eğlenceli bir deney:

$ a='['
$ $a -d . ]
$ echo $?
0

Bash [ satırını ayrıştırdığında, özel bir şey (yani, takma adlar, yönlendirme yok, anahtar sözcük yok) görmez, bu nedenle yalnızca değişken genişleme gerçekleştirir. Değişken açılımlardan sonra şunu görür:

[ -d . ]

öyleyse $a -d . ] , [ ve -d argümanları ile . komutunu çalıştırır (ki bu% s_de% 'nin bir dizin olup olmadığını test eder).

Şimdi bak:

$ a='[['
$ $a -d . ]]
bash: [[: command not found

Ah. Çünkü Bash bu çizgiyi gördüğü zaman, özel bir şey görmez ve dolayısıyla tüm değişkenleri genişletir ve sonunda görür:

[[ -d . ]]

Şu anda, takma uzantılar ve anahtar kelime taraması uzun süredir gerçekleştirildi ve artık gerçekleştirilmeyecek, bu nedenle Bash ] adlı komutu bulmaya çalışıyor, bulamıyor ve şikayet ediyor.

Aynı satırlarda:

$ '[' -d . ]
$ echo $?
0
$ '[[' -d . ]]
bash: [[: command not found

ve

$ \[ -d . ]
$ echo $?
0
$ \[[ -d . ]]
bash: [[: command not found

Alias ​​genişletme de oldukça özel bir şeydir. Hepiniz en az bir kez aşağıdakileri yaptınız:

$ alias ll='ls -l'
$ ll
.... <list of files in long format> ....
$ \ll
bash: ll: command not found
$ 'll'
bash: ll: command not found

Akıl yürütme aynıdır: takma genişletme ve alıntı kaldırma işleminden çok önce takma ad uzatma gerçekleşir.

Anahtar kelime v.s. Alias ​​

Şimdi bir anahtar kelime olarak takma ad tanımlarızsa ne olacağını düşünüyorsunuz?

$ alias mytest='[['
$ mytest -d . ]]
$ echo $?
0

Oh, işe yarıyor! Bu yüzden takma adlar, anahtar kelimeleri taklit etmek için kullanılabilir! bilmek güzel.

Sonuç: yerleşimler gerçekten komutlar gibi davranırlar: doğrudan değişken genişleme ve kelime bölme ve sallanma süreçlerine maruz kalan argümanlarla yürütülen bir eyleme karşılık gelirler. Değişken genişleme, vb. Sonra verilen argümanlarla çağrılan . veya [[ değerindeki bir yerde bir dış komut olması gibi bir şey. dediğimde, gerçekten de bir dış komut olması gibi. Ben sadece argümanlar, kelime bölme, globbing, değişken genişleme vb. Anlamındayım. Bir yerleşik, kabuğun dahili durumunu değiştirebilir!

Diğer taraftan, anahtar kelimeler taranır ve çok erken anlaşılır ve gelişmiş kabuk davranışı sağlar: Kabuk, kelime bölme veya yol adı genişletme, vb. yasaklayabilir.

Artık, yerleşik anahtar kelimelere ve anahtar kelimelere bakın ve neden bazılarının anahtar kelime olması gerektiğini anlamaya çalışın.

/bin bir anahtar kelimedir. Davranışlarını bir işlevle taklit etmek mümkün görünüyor:

not() {
    if "[email protected]"; then
        return false
    else
        return true
    fi
}

Ancak bu, aşağıdaki gibi yapıları yasaklayabilir:

$ ! ! true
$ echo $?
0

veya

$ ! { true; }
echo $?
1

/usr/bin için aynı: Bir anahtar kelimeye sahip olmak daha karmaşıktır, böylece karmaşık bileşik komutları ve boru hatlarını yeniden yönlendirmelerle zamanlayabilirsiniz:

$ time grep '^#' ~/.bashrc | { i=0; while read -r; do printf '%4d %s\n' "$((++i))" "$REPLY"; done; } > bashrc_numbered 2>/dev/null

! , sadece bir komut (hatta yerleşik) ise, yalnızca time , time ve grep argümanlarını görecek, bunu zaman alacak ve daha sonra çıkışı boru hattının kalan kısımlarından geçecektir. . Ama bir anahtar kelime ile Bash her şeyi halledebilir! Yeniden yönlendirmeler de dahil olmak üzere, tüm boru hattının%% sini kullanabilir! % Co_de% salt bir komut ise, yapamadık:

$ time { printf 'hello '; echo world; }

Deneyin:

$ \time { printf 'hello '; echo world; }
bash: syntax error near unexpected token '}'

Düzeltmeyi deneyin (?):

$ \time { printf 'hello '; echo world;
time: cannot run {: No such file or directory

umutsuz.

Anahtar kelime ile takma ad mı?

$ alias mytime=time
$ alias myls=ls
$ mytime myls

Ne olduğunu düşünüyorsun?

Gerçekten, yerleşik komutta olduğu gibi bir kabuk gibidir, oysa bir anahtar kelime , karmaşık davranışlara izin veren bir şeydir! Kabuğun dilbilgisinin bir parçası olduğunu söyleyebiliriz.

    
verilen cevap gniourf_gniourf 26.02.2015 19:57
8

man bash , onları SHELL BUILTIN COMMANDS olarak adlandırıyor. Yani, bir "kabuk yerleşiği", grep gibi bir normal komut gibidir, ancak ayrı bir dosyada bulunmak yerine, bashın kendisine yerleştirildi . Bu onların harici komutlardan daha verimli çalışmasını sağlar.

anahtar kelimesi de Bash’e kodlanmıştır, ancak Bir anahtar kelime kendi başına bir komut değil, bir komut yapısının bir alt birimi. " Bunu, anahtar kelimelerin tek başına hiçbir işleve sahip olmadığı, ancak herhangi bir şey yapması için komutlar gerektirdiği anlamına gelir. (Bağlantıdan diğer örnekler for , while , do ve ! , ve daha fazlası cevabım diğer sorunuza.)

    
verilen cevap Sparhawk 10.04.2014 04:58
1

Ubuntu ile gelen komut satırı elkitabı bir anahtar kelime tanımı vermez, ancak çevrimiçi el kitabı (bkz. Sidenote) ve POSIX Kabuk Komut Dili standart özellikleri , "Ayrılmış Kelimeler" olarak adlandırın ve her ikisinin de listelerini sağlayın. POSIX standardından:

  

Bu tanıma, yalnızca karakterlerin hiçbiri alıntı yapılmadığında ve sözcük şu şekilde kullanıldığında gerçekleşir:

     
  • Bir komutun ilk sözcüğü

  •   
  • Hariç, kayıt veya

  • dışındaki ayrılmış sözcüklerden birini izleyen ilk kelime   
  • Bir vaka komutundaki üçüncü sözcük (yalnızca bu durumda geçerlidir)

  •   
  • Bir for komutundaki üçüncü sözcük (yalnızca bu durumda geçerlidir ve geçerlidir)

  •   

Buradaki anahtar, anahtar sözcüklerin / ayrılmış kelimelerin özel anlamlara sahip olmasıdır, çünkü kabuk sözdizimini kolaylaştırır, döngüler, bileşik komutlar, dallanma (if / durum) ifadeleri gibi belirli kod bloklarını işaret ederler. ifadeler, ancak kendi başlarına bir şey yapmazsınız ve aslında for , until , case gibi anahtar kelimeler girerseniz, kabuk aksi takdirde tam bir ifade bekler - sözdizimi hatası:

$ for
bash: syntax error near unexpected token 'newline'
$  

Kaynak kod düzeyinde, bash için ayrılan kelimeler parese olarak tanımlanmıştır. y , yerleşik yerleşiklerin kendilerine adanmış dizinin tamamı var.

Sidenote

GNU dizini ayrılmış sözcük olarak [ gösterir, ancak gerçekte yerleşik komuttur. Kontrast ile [[ ayrılmış bir kelimedir.

Ayrıca bkz .: Anahtar kelime, ayrılmış kelime ve yerleşik arasındaki farklar

    
verilen cevap Sergiy Kolodyazhnyy 16.07.2018 00:41

Etiketlerdeki diğer soruları oku