$ BASH_COMMAND değişkeni ne için iyidir?


25

Göre Bash kılavuzda , ortam değişkeni BASH_COMMANDiçeren

Şu anda yürütülmekte olan ya da yürütülmek üzere olan komut, kabuk bir tuzağın sonucu olarak bir komut çalıştırmadığı sürece, bu durumda tuzak anında çalışan komuttur.

Bu tuzak köşesi örneğini bir kenara çekmek, eğer doğru anlarsam, bir komutu yürüttüğümde, değişkenin BASH_COMMANDbu komutu içerdiği anlamına gelir . Kesinlikle bu değişken komut yürütme sonrasında ayarlanmazsa olmadığını açık değil (yani sadece avaialble iken kimse olduğu için "komutu iddia edebilir rağmen komut ancak sonra çalıştığı) şu anda infaz veya varlık edilmek üzere yürütülen" , sadece yürütülen komut değildir .

Ama kontrol edelim:

$ set | grep BASH_COMMAND=
$ 

Boş. Görmeyi beklerdim BASH_COMMAND='set | grep BASH_COMMAND='ya da belki sadece BASH_COMMAND='set', ama boş beni şaşırttı.

Başka bir şey deneyelim:

$ echo $BASH_COMMAND
echo $BASH_COMMAND
$ 

Bu mantıklı. Komutu çalıştırdım echo $BASH_COMMANDve değişken BASH_COMMANDdizgiyi içeriyor echo $BASH_COMMAND. Neden bu sefer işe yaradı, ama daha önce olmadı?

setYine bir şey yapalım :

$ set | grep BASH_COMMAND=
BASH_COMMAND='echo $BASH_COMMAND'
$

Öyleyse bekle. O edildi O çalıştırıldığında set echokomutu ve değildi sonradan tanımsız. Ben çalıştırıldığında Ama setyine BASH_COMMAND değildi ayarlı setkomuta. setBuradaki komutu ne sıklıkta çalıştırsam da , sonuç aynı kalıyor. Öyleyse, değişken yürütülürken ayarlanır mı, çalıştırılırken echodeğil setmi? Bakalım.

$ echo Hello AskUbuntu
Hello AskUbuntu
$ set | grep BASH_COMMAND=
BASH_COMMAND='echo $BASH_COMMAND'
$

Ne? Değişken yüzden çalıştırıldığında kuruldu echo $BASH_COMMAND, ama değil ben yürütüldüğünde echo Hello AskUbuntu? Şimdi fark nerede? Değişken yalnızca geçerli komutun kendisi aslında kabuğu değişkeni değerlendirmek için zorladığında mı ayarlanır? Farklı bir şey deneyelim. Belki bu sefer bazı dış komutlar, bir bash yerleşik değil, bir değişiklik için.

$ /bin/echo $BASH_COMMAND
/bin/echo $BASH_COMMAND
$ set | grep BASH_COMMAND=
BASH_COMMAND='/bin/echo $BASH_COMMAND'
$

Hmm, tamam ... tekrar, değişken ayarlandı. Peki şimdiki tahminim doğru mu? Değişken, yalnızca değerlendirilmesi gerektiğinde ayarlandı mı? Niye ya? Niye ya? Performans nedeniyle mi? Bir tane daha deneyelim. $BASH_COMMANDBir dosyada grep yapmaya çalışacağız ve o $BASH_COMMANDzaman bir grepkomut içermeli , grepo grepkomut için grep yapmalı (yani kendisi için). öyleyse uygun bir dosya yapalım:

$ echo -e "1 foo\n2 grep\n3 bar\n4 grep \$BASH_COMMAND tmp" > tmp
$ grep $BASH_COMMAND tmp
grep: $BASH_COMMAND: No such file or directory
tmp:2 grep                                      <-- here, the word "grep" is RED
tmp:4 grep $BASH_COMMAND tmp                    <-- here, the word "grep" is RED
tmp:2 grep                                      <-- here, the word "grep" is RED
tmp:4 grep $BASH_COMMAND tmp                    <-- here, the word "grep" is RED
$ set | grep BASH_COMMAND=
BASH_COMMAND='grep --color=auto $BASH_COMMAND tmp'
$

Tamam, ilginç. Komut grep $BASH_COMMAND tmpgenişletildi grep grep $BASH_COMMAND tmp tmp(değişken, elbette sadece bir kez genişledi) ve böylece grep, bir kez $BASH_COMMANDvar olmayan bir dosyada ve iki kez de dosyada elimde tmp.

S1: Mevcut varsayımım doğru mu:

  • BASH_COMMANDsadece bir komut gerçekten değerlendirmeye çalıştığında ayarlanır; ve
  • o olduğu değil açıklamayla inanmak bize yol olsa bile, bir komutun yürütülmesi sonra unset?

S2: Evet ise neden? Performans? Hayır ise, yukarıdaki komut sırasındaki davranış başka nasıl açıklanabilir?

S3: Son olarak, bu değişkenin gerçekten anlamlı bir şekilde kullanılabileceği bir senaryo var mı? $PROMPT_COMMANDYürütülmekte olan komutu analiz etmek için aslında onu kullanmaya çalışıyordum (ve buna bağlı olarak bazı şeyler yapıyordum), ancak yapamıyorum, çünkü en kısa sürede $PROMPT_COMMAND, içimde değişkene bakmak için bir komut $BASH_COMMANDyürütüyorum bu komuta ayarlar. MYVARIABLE=$BASH_COMMANDBenim başlangıcımda doğru yaptığımda bile $PROMPT_COMMAND, o zaman MYVARIABLEdizeyi içerir MYVARIABLE=$BASH_COMMAND, çünkü bir atama da bir komuttur. (Bu soru şu anki komutu bir $PROMPT_COMMANDyürütme içinde nasıl elde edebileceğimle ilgili değil . Bildiğim başka yollar da var.)

Heisenberg'in belirsizlik ilkesine benziyor. Sadece değişkeni gözlemleyerek değiştiririm.


5
Güzel, ama unix.stackexchange.com için muhtemelen daha uygun ... orada gerçek bashüber-gurular var.
Rmano

Peki, oraya taşımak mümkün mü? Değişiklikler?
Malte Skoruppa

Nasıl yapılacağından emin değilim --- Sanırım bu bir Mod ayrıcalığı. Öte yandan, işaretlemenin mantıklı olduğunu düşünmüyorum --- bakalım biri yakın bayrak üzerinde hareket ediyor mu?
Rmano

1
Üçüncü nokta için, bu aradığınız budur. Belki de bu makaleye dayanarak ilk iki puanın cevabını da bulabilirsiniz.
Radu Rădeanu

2
+1 kafamı karıştırdı ama okumak eğlenceli oldu!
Joe,

Yanıtlar:


15

Üçüncü soruya cevap vermek: Tabii ki Bash kılavuzunda açıkça kullanılabilecek şekilde kullanılabilir - bir tuzakta, örneğin:

$ trap 'echo ‘$BASH_COMMAND’ failed with error code $?' ERR
$ fgfdjsa
fgfdjsa: command not found
fgfdjsa failed with error code 127
$ cat /etc/fgfdjsa
cat: /etc/fgfdjsa: No such file or directory
cat /etc/fgfdjsa failed with error code 1

Ah, gerçekten güzel. Öyleyse, bir tuzağın bu değişkenin anlamlı olduğu tek bağlam olduğunu söyler misiniz? Kılavuzdaki bir köşe davası gibi geldi: " Kabuk bir tuzak sonucu bir komut çalıştırmıyorsa, komut çalıştırılıyor (...) , ..."
Malte Skoruppa

@DocSalvager'ın cevabında yer alan makaleleri okuduktan sonra $BASH_COMMAND, gerçekten bir tuzak dışındaki bağlamlarda bile anlamlı bir şekilde kullanılabileceği açıktır . Yine de, tarif ettiğiniz kullanım muhtemelen en tipik ve en basit yöntemdir. Cevabınız ve DocSalvager teker Yani, benim cevap Q3 iyi ve bu benim için en önemli idi. Qz ve Q2'ye gelince, @zwets tarafından belirtildiği gibi, bunlar tanımsızdır. O olabilir $BASH_COMMANDya da başka bazı garip iç program koşulları bu davranışa yol açabilir - performans için, erişilen keşke bir değer verilir. Kim bilir?
Malte Skoruppa

1
Bir dipnot düşmek gerekirse, bunu keşfetti olabilir zorlamak $BASH_COMMANDdeğerlendirmesini zorlayarak, her zaman ayarlanması $BASH_COMMANDher komutun önce. Bunu yapmak için, her bir komuttan önce (tümü em) yürütülen DEBUG tuzağını kullanabiliriz. Biz sorunu varsa, örneğin trap 'echo "$BASH_COMMAND" > /dev/null' DEBUG, daha sonra $BASH_COMMANDher zaman her komutun önce değerlendirilir (ve bu değeri atanacaktır $COMMAND). Eğer set | grep BASH_COMMAND=tuzak aktifken idam edersem ... ne biliyorsun? Şimdi çıktı, BASH_COMMAND=setbeklendiği gibi :)
Malte Skoruppa

6

Şimdi Q3 cevaplandı (doğru, bence: BASH_COMMANDtuzaklarda ve başka hiçbir yerde kullanışsız), hadi Q1 ve Q2'ye bir şans verelim.

S1'in cevabı şudur: Varsayımınızın doğruluğu kararsız. Belirtilmemiş davranışlar hakkında soru sorarken, hiçbir mermi noktasının gerçekliği belirlenemez. Spesifikasyonuna göre, değeri BASH_COMMAND, o komutun yürütülmesi süresince bir komutun metnine ayarlanır. Spesifikasyon, başka bir durumda, yani herhangi bir komut yürütülmediğinde, değerinin ne olması gerektiğini belirtmez. Herhangi bir değeri olabilir ya da hiç olmayabilir.

S2 cevabı "Hayır ise, yukarıdaki komut sırasındaki davranış başka nasıl açıklanabilir?" daha sonra mantıksal olarak (biraz bilgiçlikle geldiyse) takip eder: değerinin BASH_COMMANDtanımsız olduğu gerçeğiyle açıklanır . Değeri tanımlanmadığından, tam olarak dizinin gösterdiği gibi herhangi bir değere sahip olabilir.

dipnot

Spesifik olarak yumuşak bir noktaya çarptığınızı düşündüğüm bir nokta var. Söylediğin yer:

MYVARIABLE = $ BASH_COMMAND 'ı doğrudan $ PROMPT_COMMAND'ımın başında yaptığımda bile, MYVARIABLE MYVARIABLE = $ BASH_COMMAND dizesini içerir, çünkü bir atama da bir komuttur .

Bash man sayfasını okudum, italik biti doğru değil. Bu bölüm SIMPLE COMMAND EXPANSIONönce komut satırındaki değişken atamalarının nasıl bir yana bırakılacağını ve ardından

Herhangi bir komut adı çıkmazsa [diğer bir deyişle, yalnızca değişken atamaları vardı], değişken atamaları mevcut kabuk ortamını etkiler.

Bu bana değişken atamalarının BASH_COMMANDdiğer programlama dillerinde olduğu gibi komut olmadığını (ve dolayısıyla gösterilmekten muaf olduğunu) göstermektedir . Bir çizgi yoksa neden o zaman da açıklıyor BASH_COMMAND=setçıktısında set, setesasen değişken atama için bir sentaks 'işaretleyici' olmak.

OTOH, bu bölümün son paragrafında diyor ki

Genişletmeden sonra kalan bir komut adı varsa, yürütme aşağıda açıklandığı şekilde ilerler. Aksi halde, komut çıkar.

... başka türlü düşündüren değişken değişkenleri de komuttur.


1
Sadece bazı varsayımların kurulamaması yanlış olduğu anlamına gelmez. Einstein, ışığın hızının, herhangi bir gözlemci için (herhangi bir hızda) görelilik teorisi için temel bir hipotez olarak aynı olduğunu varsaydı; Bu kurulamaz, ancak bu yanlış olduğu anlamına gelmez. "Kurulabilir" ve "doğru" özellikleri ortogonaldir. En iyi ihtimalle "Doğru olup olmadığını bilmiyoruz, çünkü kurulamaz" diyebilirsiniz. Ayrıca, bir belirtilen: Bu yürütme sırasında geçerli bir komut. Öyleyse setBASH_COMMAND='set'
yazarsam

... ancak durum böyle değil. Bu komutun yürütülmesi sırasındaset olmasına rağmen . Bu nedenle, özelliklerine göre çalışması gerekir. Öyleyse, uygulama şartnamelere tam olarak uymuyor mu, yoksa özellikleri yanlış mı anladım? Bu sorunun cevabını bulmak Q1'in bir nevi amacıdır.
Metniniz

@MalteSkoruppa İyi puanlar. Cevap buna göre düzeltildi ve hakkında bir açıklama eklendi set.
zwets

1
Bash tercümanında setbir "komut" olmayabilir. Tıpkı =bir "komut" olmadığı gibi . Bu belirteçleri takip eden / çevreleyen metnin işlenmesi, bir "komut" işlemesinden tamamen farklı bir mantığa sahip olabilir.
DocSalvager

İkinizden de iyi puanlar. :) Bu setbir "komut" olarak sayılmaz olabilir . Ben düşünce olmazdı $BASH_COMMANDaçacak kadar çok durumlarda underspecified edilecek. Sanırım en azından man sayfasının bu konuda kesinlikle daha net olabileceğini
saptadık

2

$ BASH_COMMAND için yaratıcı bir kullanım

Son zamanlarda makro benzeri bir işlevselliğin uygulanmasında $ BASH_COMMAND'ın bu etkileyici kullanımını buldum .

Bu, takma adın çekirdek numarasıdır ve DEBUG tuzağının kullanılmasının yerine geçer. DEBUG tuzağı hakkındaki önceki yazıdaki bölümü okursanız, $ BASH_COMMAND değişkenini tanırsınız. Bu yazıda, DEBUG tuzağına her çağrıdan önce komut metnine ayarlandığını söyledim. Her komutun yürütülmesinden önce DEBUG tuzağı ya da hayır komutunun verildiği anlaşılıyor (örneğin, neyi konuştuğumu görmek için 'echo “bu komut = $ BASH_COMMAND”' komutunu çalıştırın). Bir değişken atayarak (sadece bu satır için) komutun en dışını kullanarak tüm komutu içerecek şekilde BASH_COMMAND değerini yakalarız.

Yazarın önceki makalesi ayrıca bir DEBUG kullanarak bir teknik uygularken bazı iyi arka plan sağlar trap. trapGeliştirilmiş modeli elimine edilir.


+1 Sonunda bu iki makaleyi okumak için geldim Vaov! Ne bir okuma! Çok aydınlatıcı. Bu adam bir bash guru ! Kudos! Bu aynı zamanda, Dmitry’ın $BASH_COMMAND, a dışında bir bağlamda anlamlı bir şekilde kullanılıp kullanılamayacağına ilişkin cevabımdaki yorumuma cevap veriyor trap. Ve bu ne işe yarar! Makro komutlarını bash içerisinde uygulamak için bunu kullanmak - kim mümkün olabilirdi ki? İşaretçi için teşekkürler.
Malte Skoruppa

0

Tuzak ... hata ayıklama için görünüşte yaygın bir kullanım, "ekran" kullanırken pencerede görünen başlıkları (^ A ") iyileştirmektir.

"Ekran", "pencere listesi" ni daha kullanışlı kılmaya çalışıyordum, bu yüzden "tuzak ... hata ayıklama" ile ilgili makaleler bulmaya başladım.

"Null başlık dizisini" göndermek için PROMPT_COMMAND kullanan yöntemin çok iyi çalışmadığını ve bu yüzden trap ... debug metoduna geri döndüğümü öğrendim.

İşte nasıl:

1 "shelltitle '$ | bash:'" 'ı "$ HOME / .screenrc" içine koyarak kaçış sırasını aramasını (etkinleştir) "ekran" a söyleyin.

2 Hata ayıklama tuzağının alt kabuklara yayılmasını kapatın. Bu önemlidir, çünkü eğer etkinse, her şey toparlanırsa, şunu kullanın: "set + o functrace".

3 Yorumlamak için "ekran" için başlık çıkış sırasını gönderin: "printf" \ ek $ tuzağı (tarih +% Y% m% d% H% M% S) $ (whoami) @ $ (ana bilgisayar adı): $ (pwd) $ {BASH_COMMAND} \ e \ "'" DEBUG "

Mükemmel değil, ama yardımcı oluyor ve tam anlamıyla istediğiniz her şeyi başlığa koymak için bu yöntemi kullanabilirsiniz

Aşağıdaki "pencere listesine" bakınız (5 ekran):

Num Name Bayrakları

1 bash: 20161115232035 mcb @ ken007: / home / mcb / ken007 RSYNCCMD = "sudo rsync" myrsync.sh -R -r "$ {1}" "$ {BACKUPDIR} $ {2: +" / $ {2} " } "$ 2 bash: 20161115230434 mcb @ ken007: / ana sayfa / mcb / ken007 ls - renk = otomatik = 3 $ bash: 20161115230504 mcb @ ken007: / ana sayfa / mcb / ken007 kedi kutusu / psg.sh $ 4 bash: 20161115222415 mcb @ ken007: / ana sayfa / mcb / ken007 ssh ken009 5 bash: 20161115222450 mcb @ ken007: / ana sayfa / mcb / ken007 mycommoncleanup $

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.