Pozisyon parametreleriyle Bash -c


15

Genellikle, $0bir komut dosyasında komut dosyasının adına veya ne olarak çağrıldığına (yol dahil) ayarlanır. Ancak, seçeneği bashile kullanırsanız , komut dizesinden sonra iletilen bağımsız değişkenlerin ilkine ayarlanır:-c$0

bash -c 'echo $0 ' foo bar 
# foo 

Aslında, konumsal parametreler değişmiş gibi görünüyor, ancak dahil $0. Ancak shiftkomut dizesinde $0(normal olarak) etkilenmez :

bash -c 'echo $0; shift; echo $0 ' foo bar
# foo
# foo

Neden bu komut dizeleri için garip davranış? Bu tür garip davranışların arkasındaki nedeni, mantığı arıyorum.


Böyle bir komut dizesinin $0genellikle tanımlandığı gibi parametreye ihtiyaç duymayacağı düşünülebilir , bu nedenle ekonomi için normal argümanlar için de kullanılır. Ancak, bu durumda davranışı shifttuhaftır. Başka bir olasılık, $0programların davranışını tanımlamak için kullanılır (la olarak bashadlandırılır shveya olarak vimadlandırılır vi), ancak bu olamaz, çünkü $0burada yalnızca komut dizesinde görülür ve içinde programlanan programlar tarafından görülmez. Bunun için başka bir kullanım düşünemiyorum $0, bu yüzden bunu açıklamak için bir kaybım var.


Bir yan not olarak, kullanımını gördük -için $0olduğu gibi bir deyim olarak argüman sh -c 'foo $1 $2' - a b. Bu şekilde oldukça normal görünüyor (bunun ne -anlama geldiğini
Volker Siegel

Ayrıca edebilir echo 'echo the other side of this pipe globs "$@"' | sh -s -- *, ama, ne yazık ki, $0genellikle bir ayarlanabilir parametre değildir -sTeam, seçenek ... Aynı yollardan birçok kullanılabilir xargsgenellikle şeyim. Ve diğerleri dışında.
mikeserv

@VolkerSiegel Daha normal olurdu --, o zaman bu, diğer bazı programlarda görülen 'buradan argümanları başlatır' olağan yorumuna sahip olabilirdi. Sonra tekrar, bu aşina olmayanların aslında bu yoruma sahip olduklarını -cdüşünmek kafa karıştırıcı olabilir --.
muru

Yanıtlar:


10

Bu size $0bir satır içi komut dosyası kullanırken ayarlama / seçme fırsatı verir . Aksi takdirde, $0sadece olurdu bash.

Sonra örneğin şunları yapabilirsiniz:

$ bash -c 'wc -c < "${1?}"' getlength foo
4
$ bash -c 'wc -c < "${1?}"' getlength bar
getlength: bar: No such file or directory
$ bash -c 'wc -c < "${1?}"' getlength
getlength: 1: parameter null or not set

Bütün mermiler bunu yapmazdı. Bourne kabuğu yaptı. Korn (ve Almquist) kabuğu ilk parametrenin $1yerine geçmesini seçti. POSIX sonunda Bourne yoluna gitti kshve ashtürevler daha sonra buna geri döndü (daha fazlası için http://www.in-ulm.de/~mascheck/various/find/#shell ). Bu, uzun bir süre boyunca sh(sisteme bağlı olarak Bourne, Almquist veya Korn kabuğuna dayanıyordu), ilk argümanın içeri girip girmediğini $0veya $1taşınabilirlik için aşağıdakileri yapmak zorunda olduğunuzu bilmediğiniz anlamına geliyordu :

sh -c 'echo foo in "$1"' foo foo

Veya:

sh -c 'shift "$2"; echo txt files are "$@"' tentative-arg0 3 2 *.txt

Neyse ki, POSIX ilk argümanın girdiği yeni davranışı belirledi $0, böylece artık portatif olarak yapabiliriz:

sh -c 'echo txt files are "$@"' meaningful-arg0-for-error *.txt

: Sadece koştum bash -c 'echo txt files are "$@"' meaningful-arg0-for-error *.txtUbuntu 14.04, bash version 4.3.11(1)-releaseve bende: txt files are *.txt. Oo
muru

2
@ doğru olan (ve muhtemelen txtgeçerli dizinde dosya yok ). Ayrıca bakınızbash -c 'echo "${1?}"' foo
Stéphane Chazelas

Ah evet. Bu pratik olarak faydalı bir örnek.
muru

1
sh -c 'shift "$2"; echo txt files are "$@"' tentative-arg0 3 2 *.txtfevkalade yaratıcıdır!
iruvar

Veya tamamen sağlam bir çözüm kullanırsınız (comp.unix.shell'de Stéphane Chazelas tarafından önerilir) SHELL -c 'shift $1; command' 2 1 arg1 arg2 ... haha ...
mikeserv

3

Bu davranış POSIX tarafından tanımlanır :

sh -c komut_adı [bağımsız değişken ...]

Komutları command_string işleneninden okuyun. Özel parametre 0'ın değerini (bkz. Özel Parametreler ), command_name işleneninin değerinden ve konumsal parametrelerin ($ 1, $ 2, vb.) Kalan argüman işlenenlerinden sırayla ayarlayın.

Neden bu davranışı istediğinize gelince: bu bir betik ve -cdize arasındaki boşluğu düzeltir . Herhangi bir davranış değişikliği olmadan doğrudan ikisi arasında dönüştürme yapabilirsiniz. Diğer alanlar, bunların aynı olmasına bağlıdır.

Ayrıca program argümanlarının genel olarak nasıl çalıştığı ile aynı doğrultudadır: bu, sonuçta execilk sağlanan argümanın da bulunduğu işlevlerden birini çağırmakla $0aynıdır ve aynı argüman, çalıştırdığınız yürütülebilir dosya ile aynıdır. Ancak bazen orada özel bir değer istersiniz ve bunu elde etmenin başka bir yolu olmazdı. Argümanın var olduğu göz önüne alındığında, bir şeye eşleme yapması gerekir ve kullanıcının bunun ne olduğunu ayarlaması gerekir.

Bu tutarlılık (ve muhtemelen tarihi kaza) bulduğunuz duruma yol açar.


İkinci paraya (umarım gerçek dünya) bir örnek verebilir misiniz?
muru

İle benzerliklere dikkat edin argv[0]. $0yalnızca, argv[0]şuna execve()benzer olduğunda geçirilir olarak ayarlanır: shveya bash. Komut dosyaları $0için, yorumlayıcıya 1, 2 ... bağımsız değişkeni olarak verilen yola (ve doğrudan yürütülen komut dosyaları için, execve () ilk yol bağımsız değişkeninden gelen) ayarlanır.
Stéphane Chazelas
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.