Bir shebang ile awk için birden fazla argüman nasıl kullanılır (yani #!)?


118

Bir shebang kullanarak bir gawk komut dosyası çalıştırmak istiyorum --re-interval. "Saf" yaklaşımı

#!/usr/bin/gawk --re-interval -f
... awk script goes here

çalışmıyor, çünkü gawk, "--re-interval -f"anlamadığı ilk argümanla çağrıldığından (boşluk etrafında bölünmemiş). Bunun için bir çözüm var mı?

Elbette ya doğrudan gawk diyemezsiniz, onu ilk argümanı bölen bir kabuk betiğine sarabilirsiniz ya da gawk'ı çağıran ve betiği başka bir dosyaya koyan bir kabuk betiği yapabilirsiniz, ama yapmanın bir yolu olup olmadığını merak ediyordum. bu tek bir dosyada.

Shebang satırlarının davranışı sistemden sisteme farklılık gösterir - en azından Cygwin'de argümanları beyaz boşluklara bölmez. Böyle davranan bir sistemde bunu nasıl yapacağımı umursuyorum; komut dosyasının taşınabilir olması amaçlanmamıştır.


1
Az önce yaptığım aptalca bir deney, argümanları doğru bir şekilde bölen, shebang satırında başka bir komut dosyası kullanan bir komut dosyasıyla oldu.
Hasturkun

Başka bir sorunu gündeme getiren @Hasturkun, çağrılan programın kendisi bir betik olup olmadığına göre, shebang satırlarının davranışının da sistemden sisteme farklılık göstermesidir.
şüphelijim


Gawk'ın son sürümlerinde (> = 4.0) --re-intervalartık gerekli değildir (bkz. [ Gnu.org/software/gawk/manual/… ).

Yanıtlar:


25

Bu benim için (g) awk ile çalışıyor gibi görünüyor.

#!/bin/sh
arbitrary_long_name==0 "exec" "/usr/bin/gawk" "--re-interval" "-f" "$0" "$@"


# The real awk program starts here
{ print $0 }

Not #!çalışır /bin/shbu komut dosyası ilk olarak bir kabuk komut dosyası olarak yorumlanır, böylece.

İlk başta denedim "exec" "/usr/bin/gawk" "--re-interval" "-f" "$0" "$@", ama awk bunu bir komut olarak ele aldı ve her girdi satırını koşulsuz olarak yazdırdı. Bu yüzden arbitrary_long_name==0her zaman başarısız olması gerekiyordu. Bunu anlamsız bir dizeyle değiştirebilirsiniz. Temel olarak, awk'ta kabuk betiğini olumsuz etkilemeyecek bir yanlış koşul arıyordum.

Kabuk betiğinde, arbitrary_long_name==0adı verilen bir değişkeni tanımlar arbitrary_long_nameve onu eşit olarak ayarlar =0.


Cevabım bu, ancak yeterince taşınabilir ve sağlam olup olmadığını merak ediyorum. Özel olarak bashherhangi bir POSIX'e bağlı mı veya herhangi bir POSIX ile çalışacak shmı? Ve awksık kullanmıyorum , bu yüzden ikinci satırdaki numaramın çizgiyi awkgörmezden gelmek için iyi bir yol olduğundan emin değilim .
Aaron McDaid

Tam da merak ettiğim şey, +1, ancak muhtemelen tavsiye edilemez (dolayısıyla göreceli oylar).
Aaron Hall

Bunun ne gibi sorunları olabileceğini açıklayabilir misin @AaronHall? Sürece değişken olarak arbitrary_long_namegerçek awk programda kullanılan bir değişken çatışma değil, ben herhangi bir sorun göremiyorum. Eksik bir şey mi var?
Aaron McDaid

İlk karakter olarak sıfırıncı bir argümanla çağrılırsa, komut dosyasını tehlikeli bir şekilde yanlış davranmaktan korumak için #!/bin/sh -yerine kullanın . Bu, argüman dizisinin bir parçası olarak çağrılan program adını ve benzer işlevlere geçirmeyi unutarak yanlışlıkla karıştırmanın kolay olduğu C gibi programlama dillerinde yanlışlıkla olabilir ve eğer insanlar alışkanlıkla buna karşı korumayı unutursa, aynı zamanda sonunda, bir saldırganın etkileşimli bir kabuk elde etmesine olanak tanıyan, kötü amaçla yararlanılabilen bir güvenlik açığının son adımı olur. #!/bin/sh-execve
mtraceur

161

Shebang satırı hiçbir zaman POSIX, SUS, LSB veya başka herhangi bir spesifikasyonun parçası olarak belirtilmemiştir. AFAIK, düzgün bir şekilde belgelenmemiş bile.

Arasındaki her şeyi alır: Bu mu hakkında bir kaba mutabakat var !ve \nve execbunun. Varsayım arasındaki her şeydir !ve \ntercüman tam bir mutlak yoludur. Beyaz boşluk içeriyorsa ne olacağı konusunda fikir birliği yoktur.

  1. Bazı işletim sistemleri her şeyi basitçe yol olarak ele alır. Sonuçta, çoğu işletim sisteminde, bir yolda boşluklar veya çizgiler yasaldır.
  2. Bazı işletim sistemleri boşlukta bölünür ve ilk bölümü yorumlayıcıya giden yol, geri kalanını ise bağımsız argümanlar olarak ele alır.
  3. Bazı işletim sistemleri ilk boşlukta bölünür ve ön kısmı yorumlayıcıya giden yol olarak ve geri kalanını tek bir argüman olarak görür (gördüğünüz şey budur).
  4. Hatta bazıları shebang çizgileri desteklemeyen hiç .

Neyse ki, 1. ve 4. yokmuş gibi görünüyor, ancak 3. oldukça yaygın, bu nedenle birden fazla argümandan geçebileceğinize güvenemezsiniz.

Ayrıca POSIX veya SUS'ta komutların konumu da belirtilmediğinden, genellikle çalıştırılabilir dosyanın adını ileterek bu tek bağımsız değişkeni kullanırsınız. etmek env, böylece o çalıştırılabilir programın konumunu belirleyebilir; Örneğin:

#!/usr/bin/env gawk

[Açıkçası, bu hala belirli bir yol varsayıyor env, ancak içinde yaşadığı çok az sistem var/bin , bu nedenle bu genellikle güvenlidir. Konumu envçok daha yerini daha standardize olduğu gawkgibi ya da daha kötüsü bir şey pythonya rubyya spidermonkey.]

Hangi aslında kullanamazsınız demekse herhangi argümanları hiç .


1
FreeBSD'nin envanteri -Sburada yardımcı olan bir anahtara sahiptir, ancak envLinux'umda mevcut değildir ve gygwin'de de bulunmadığından şüpheleniyorum. @hstoerr, farklı durumlara sahip diğer kullanıcılar sorularınızı daha sonra okuyor olabilir, bu nedenle artık taşınabilirliğe ihtiyacınız olmasa bile genel olarak taşınabilir yanıtlar tercih edilir.
şüphelijim

4
Dolayısıyla, bir shebang'da argümanları taşınabilir bir şekilde kullanamayız. Ama ya gerekli herhangi bir şekilde argümanlara ihtiyacımız olursa? Ben çözüm sarıcı kabuk komut dosyası içeren yazmak için olduğunu tahmin ediyorum #!/bin/shve /usr/bin/env gawk --re-interval -f my-script.awk. Bu doğru mu?
Rory O'Kane

1
Katılmıyorum. Oldukça taşınabilir bir argüman kullanabilirsiniz. Herhangi bir argüman kullanamayacağınız herhangi bir sistem, bu geleneksel Unixizmi uygulamakta sefil bir şekilde başarısız olur, bu da hash-bang'tır. Gerçekleştirilmeyen uygulamalar adil bir oyunsa, #!taşınabilir olmadığını rahatlıkla söyleyebiliriz . Örneğin, Windows bu kuralı "doğal olarak" hiç tanımıyor. Unix'te geleneksel olarak yapabilmek için tek argümanlı patlama gereklidir #!/usr/bin/awk -f.
Kaz

7
@Kaz: Evet, ancak birçok ikilinin yolları standartlaştırılmadığından, tek bir argümanınızı #!/usr/bin/env rubyveya benzerlerini kullanıyorsunuz.
Jörg W Mittag

3
@Pacerier: POSIX özelliğini değiştirin ve tüm sistemler spesifikasyonla uyumlu olacak şekilde güncellenene kadar 20-30 yıl bekleyin.
Jörg W Mittag

18

Tam olarak taşınabilir olmasa da, coreutils 8.30'dan başlayarak ve belgelerine göre aşağıdakileri kullanabilirsiniz:

#!/usr/bin/env -S command arg1 arg2 ...

Yani verilen:

$ cat test.sh
#!/usr/bin/env -S showargs here 'is another' long arg -e "this and that " too

Alacaksın:

% ./test.sh 
$0 is '/usr/local/bin/showargs'
$1 is 'here'
$2 is 'is another'
$3 is 'long'
$4 is 'arg'
$5 is '-e'
$6 is 'this and that '
$7 is 'too'
$8 is './test.sh'

ve merak ediyorsanız showargs:

#!/usr/bin/env sh
echo "\$0 is '$0'"

i=1
for arg in "$@"; do
    echo "\$$i is '$arg'"
    i=$((i+1))
done

Orijinal cevap burada .


1
Bilginize, FreeBSD yıllardır -S'ye sahiptir (6.0'dan beri). Bu, temel araçlara hoş bir taşınabilirlik ekidir.
Juan

12

Aynı sorunla karşılaştım, beyaz boşlukların bir shebang'da (en azından Linux'ta) ele alınış şekli nedeniyle görünürde bir çözüm olmadan.

Bununla birlikte, kısa seçenekler oldukları ve birleştirilebildikleri sürece (GNU yolu) , bir shebang içinde birkaç seçenek iletebilirsiniz .

Örneğin, sahip olamazsınız

#!/usr/bin/foo -i -f

ama alabilirsin

#!/usr/bin/foo -if

Açıkçası, bu yalnızca seçeneklerin kısa eşdeğerleri olduğunda ve hiçbir argüman almadığında işe yarar.


11

Cygwin ve Linux altında, shebang'ın yolundan sonraki her şey programa tek bir argüman olarak ayrıştırılır.

awkShebang içinde başka bir komut dosyası kullanarak bunu aşmak mümkündür:

#!/usr/bin/gawk {system("/usr/bin/gawk --re-interval -f " FILENAME); exit}

Bu, {system("/usr/bin/gawk --re-interval -f " FILENAME); exit}awk olarak yürütülecektir .
Ve bu, /usr/bin/gawk --re-interval -f path/to/your/script.awksistem kabuğunuzda yürütülecektir .


2
senaryoya argümanlar verdiyseniz bu işe yaramaz
Steven Penny

4
#!/bin/sh
''':'
exec YourProg -some_options "$0" "$@"
'''

Yukarıdaki shell shebang hilesi daha taşınabilir /usr/bin/env.


Orijinal çözümüm bir python betiği için olduğu için '' ':' bir engeldir, bu nedenle '' ':' python yorumlayıcısına exec bölümünü göz ardı etmesini söyler.
user3123730

4
Sanırım sizin çözümünüz için olumsuz oy alıyorsunuz python, ama bu soru bununla ilgili awk.
Aaron McDaid

1
Python için harika bir hack.
Zaar Hai

3

Gawk kılavuzunda (http://www.gnu.org/manual/gawk/gawk.html), 1.14 bölümünün sonu, bir shebang satırından gawk çalıştırırken yalnızca tek bir argüman kullanmanız gerektiğini unutmayın. İşletim sisteminin gawk yolundan sonraki her şeyi tek bir argüman olarak ele alacağını söylüyor. Belki --re-intervalseçeneği belirlemenin başka bir yolu vardır ? Belki de betiğiniz kabuğunuza shebang satırında başvurabilir, gawkbir komut olarak çalıştırabilir ve betiğinizin metnini bir "buradaki belge" olarak içerebilir.


Görünüşe göre seçeneği belirlemenin başka yolu yok. Haklısınız: gawk -f - << EOF, bazı betik satırları, EOF çalışıyor, ancak gawk ile standart girişi okumamı engelliyor.
Hans-Peter Störr

Buradaki belge, için standart girdi akışını yer gawk, ancak yine de bir şeyi stderr üzerinden aktarabilirsiniz (yani, bu betiğe borulamadan önce stdout'u stderr'e yönlendirebilirsiniz). Aslında bunu hiç denemedim, ancak ilk işlem stderr üzerinde hiçbir şey yaymadığı sürece işe yarayabilir. Başka hiçbir şeyin kullanmadığından emin olmak istiyorsanız, adlandırılmış bir kanal ( linuxjournal.com/content/using-named-pipes-fifos-bash ) da oluşturabilirsiniz .
bta

3

Neden bashve gawkkendisini, geçmiş shebang'ı atlamak, komut dosyasını okumak ve ikinci bir örneğine bir dosya olarak iletmek için kullanmıyorsunuz gawk [--with-whatever-number-of-params-you-need]?

#!/bin/bash
gawk --re-interval -f <(gawk 'NR>3' $0 )
exit
{
  print "Program body goes here"
  print $1
}

(-Aynı doğal olarak örneğin sedveya ile de başarılabilir tail, ancak bence sadece kendine bashve gawkkendisine bağlı bir güzellik var ;)


0

Sadece eğlence için: stdin'i ve programı 3 ve 4 numaralı dosya tanımlayıcıları aracılığıyla yeniden yönlendiren aşağıdaki oldukça garip bir çözüm var. Ayrıca komut dosyası için geçici bir dosya da oluşturabilirsiniz.

#!/bin/bash
exec 3>&0
exec <<-EOF 4>&0
BEGIN {print "HALLO"}
{print \$1}
EOF
gawk --re-interval -f <(cat 0>&4) 0>&3

Bununla ilgili can sıkıcı bir şey var: Kabuk, betik üzerinde değişken genişletme yapıyor, bu yüzden her $ 'ı (betiğin ikinci satırında yapıldığı gibi) ve muhtemelen bundan daha fazlasını alıntılamalısınız.


-1

Taşınabilir bir çözüm için kullanmak awkyerine gawkstandart Bourne kabuğu (çağırmak, /bin/shsizin shebang ile) ve çağırmak awkyerine stdin yoluyla daha belgelemek bir buraya olarak komut satırında programını geçen doğrudan:

#!/bin/sh
gawk --re-interval <<<EOF
PROGRAM HERE
EOF

Not: hayır -fiçin argüman awk. Bu, girişleri okumak stdiniçin kullanılabilir durumda awkkalır. Eğer var varsayarsak gawkyüklenmiş ve sizinle ilgili şu PATH, ben orijinal örnekle yapmaya çalışıyorduk düşünüyorum herşeyi başarır (eğer awk komut dosyası değil senin shebang yaklaşım olarak ele düşünüyorum girdi olmak dosya içeriğini istediği varsayılarak ).


3
Bu benim için işe yaramadı. Baş adamı <<< blabla blabla'yı stdin'e koyar diyor. << - EOF mu demek istediniz? Her iki durumda da, bu aynı zamanda programı stdin'e koyar.
Hans-Peter Störr
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.