Çift tire (-) ile başlayan bu şey nasıl çalışır?


14

RosettaCode sayfasında aşağıdaki türden bir şey buldum:

--() { :; }; exec db2 -txf "$0"

Db2 için ve Postgres için de benzer bir şey. Ancak, bütün çizgiyi anlamıyorum.

Çift çizgi SQL'de bir yorum olduğunu biliyorum ve bundan sonra dosya kendini dosya olarak geçen bazı parametrelerle Db2 yürütülebilir çağırır. Peki ya parantez, kıvırcık parantez, iki nokta üst üste ve iki nokta üst üste ve nasıl gerçek bir hanımefendi #! ?

https://rosettacode.org/wiki/Multiline_shebang#PostgreSQL

Yanıtlar:


18

İlgili: Hangi kabuk yorumlayıcısı hiç kodsuz bir senaryo çalıştırır?

Betiğin, #!bir çift çizgi olmadığı için bir shebang / hashbang / satırı yoktur #!.

Ancak, komut dosyası bir kabuk tarafından yürütülür (yukarıdaki bağlantılı soru ve yanıtlara bakın) ve bu kabukta, -işlev adında geçerli bir karakter varsa , satır --, hiçbir şey yapmayan (iyi çalışır :, hiçbir şey yapmaz ) ve asla çağrılmaz.

İşlev, daha yaygın çok satırlı gösterimde (sadece neye benzediğini daha açık hale getirmek için, garip adı aslında bir işlev olduğu gerçeğini gizler):

-- () {
  :
}

İşlev tanımının tek amacı, kabuk betiğinde geçerli olan bir satıra ve aynı zamanda geçerli bir SQL komutuna (yorum) sahip olmaktır. Bu tür kodlara çokglot denir .

Sahte kabuk işlevini bildirdikten sonra, komut dosyası, bir kabuk komut dosyası yorumlayıcısı tarafından yürütüldüğünde exec, geçerli kabuğu , komut satırından komut dosyasının yol adında db2 -txf "$0"kullanılanla aynı olacak şekilde çalışan işlemden değiştirmek için kullanır db2 -txf.

Bu hile muhtemelen Bourne kabuğunun dashveya diğer ashtemelli kabukların, yashBourne kabuğunun ksh88veya bu kabuğun adı tire işareti olan işlevleri kabul etmediği gibi ksh93kullanıldığı sistemlerde güvenilir bir şekilde çalışmaz /bin/sh.

Ayrıca:


Aşağıdakilerin de işe yaradığını varsayalım (gerçekten test edilmedi):

--() { exec db2 -txf "$0"; }; --

@ilkkachu Şimdi daha mı?
Kusalananda

1
Oh evet! Ve bana bu tür şeylerin ne olduğunu hatırlattığın için teşekkürler. :)
ilkkachu

6

@Kusalananda'nın daha önce söylediği gibi, bu hile bozuldu ve tüm kabuklarda çalışmaz.

İşte portatif olarak bunu benim almak:

--/.. 2>/dev/null; exec db2 -txf "$0"

--Geçerli klasörde adında bir dosya / dizin bulunsa ve hatalar 2>/dev/null; sonra kabuk ikinci komut olan exec.


Hala gerçekten taşınabilir değil. Bu geçerli bir komut dosyası değil ve hala çekirdeğin komut dosyasını çalıştırmayı reddedeceği ve ENOEXECdenerseniz geri döneceği gerçeği üzerinde çalışmak için arama kabuğuna güveniyorsunuz . straceNe demek istediğimi görmek için betiği çalıştırmayı deneyin .
kasperd

@kasperd, hala taşınabilir olmalı, kabuğun üzerinde çalışmazsa komut dosyasını kabuk komut dosyası olarak çalıştırması gerekiyor exec(). "Execl () işlevi, [ENOEXEC] hatasına eşdeğer bir hata nedeniyle başarısız olursa, kabuk ilk işleneni olarak komut adıyla çağrılan bir kabuğa sahip olmak için eşdeğer bir komut yürütür ..." (bkz. Pubs.opengroup .org / onlinepubs / 9699919799.2018edition / utilities /… )
ilkkachu

@ilkkachu Ancak komut dosyaları her zaman bir kabuktan yürütülmez. Komut dosyasını yürütülebilir dosyanın çalışacağı başka bir bağlamda kullanmaya çalışırsanız başarısız olur. Ayrıca mermiler hangi tercümanın kullanılacağı konusunda anlaşamazlar. Böylece, betiğiniz artık hangi bağlamdan çağrıldığına bağlı olarak farklı davranacak veya tamamen başarısız olacaktır.
kasperd

@kasperd, elbette, exec()bir kabuktan başka bir şeyden doğrudan yaparsanız işe yaramaz . Fakat bu durum ne olurdu? Senaryoyu cronböyle ya da böyle çalıştırmak isteyebilirsiniz , ama bence her şeyi zaten bir kabuktan geçiriyor, ve olmasa bile, bu db2 -txf /path/to/scriptdurumda sadece bir kez yapmanız gerektiğinden heceleme kolaydır . Steno çalışmasına sahip olmak çoğunlukla etkileşimli bir kabukta yararlıdır. Ancak, ayrı bir sarmalayıcı komut dosyası daha sağlam olabilir.
ilkkachu

1
@kasperd Sizi dokümanlar ve standartlarla rahatsız etmeyeceğim; sadece dene! echo 'int main(int c,char**a){execvp(a[1],a+1);}' | cc -include unistd.h -xc -; echo echo yeah > a.sh; chmod 755 a.sh; ./a.out ./a.sh; PATH=`pwd` ./a.out a.sh
Billy Amca
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.