Bir kabuk betiğinde $ {1 + “$ @”} ne anlama geliyor ve “$ @” dan ne farkı var?


43

Perl belgelerinde, perlrun (1) iki dilli bir kabuk / Perl başlığı kullanarak Perl komut dosyalarının başlatılmasını önerir:

#!/bin/sh
#! -*-perl-*-
eval 'exec perl -x -wS $0 ${1+"$@"}'
    if 0;

Ne ${1+"$@"}demek istiyorsun? Bunun "$@"yerine kullanmayı denedim (Bash / bin / sh olarak kullanıldı) ve aynı şekilde çalışıyor gibi görünüyor.


Düzenle

Aşağıdaki iki cevap, olması gerektiğini söylüyor ${1:+"$@"}. ${parameter:+word}Bash (1) 'de belgelenen ("Alternatif Değer Kullan") sözdiziminin farkındayım . Ancak ikna olmadım, çünkü

  1. Her ikisi de ${1+"$@"}ve "$@"hiçbir parametresi olmasa bile gayet iyi çalışıyor. Simple.sh olarak oluşturursam

    #!/bin/sh
    eval 'exec /usr/bin/perl -x -S -- $0 "$@"'
        if 0;
    #!perl
    use Data::Dumper;
    print Dumper(\@ARGV);

    ve soru olarak

    #!/bin/sh
    eval 'exec /usr/bin/perl -x -S -- $0 ${1+"$@"}'
        if 0;
    #!perl
    use Data::Dumper;
    print Dumper(\@ARGV);

    İkisinin de aynı şekilde çalışmasını sağlayabilirim:

    $ ./question.sh 
    $VAR1 = [];
    $ ./question.sh a
    $VAR1 = [
              'a'
            ];
    $ ./question.sh a 'b c'
    $VAR1 = [
              'a',
              'b c'
            ];
    $ ./question.sh ""
    $VAR1 = [
              ''
            ];
    $ ./simple.sh 
    $VAR1 = [];
    $ ./simple.sh a
    $VAR1 = [
              'a'
            ];
    $ ./simple.sh a 'b c'
    $VAR1 = [
              'a',
              'b c'
            ];
    $ ./simple.sh ""
    $VAR1 = [
              ''
            ];
  2. İnternetteki diğer kaynaklar da ${1+"$@"}, ne yaptığını biliyor gibi görünen bir bilgisayar korsanı dahil olmak üzere kullanıyor .

Belki de ${parameter+word}belgelenmemiş bir alternatif (veya kullanımdan kaldırılmış) sözdizimi içindir ${parameter:+word}? Birisi bu hipotezi doğrulayabilir mi?


Yanıtlar:


53

Bourne kabuğuyla uyumluluk için. Bourne kabuğu, ilk olarak 1979'da Unix sürüm 7 ile piyasaya sürülen eski bir /bin/shkabuktu ve çoğu ticari Unices'da olduğu gibi 90'lı yılların ortalarına kadar da yaygındı .

Bu en atası olan Bourne benzeri kabukları gibi ksh, bashya da zsh.

Birçoğu sabitlenmiş ksh, diğer kabukları ve shbunlardan biri olan yeni standart şartnamede bazı garip özelliklere sahipti :

Bourne kabuğuyla (en azından sabitlenmemiş varyantlar): hiç bir argüman değil, "$@"konumsal parametrelerin listesi boşsa ( $# == 0) boşsa, bir boş argümana genişler .

${var+something}$varayarlanmadıkça “bir şeye” genişler . Tüm mermilerde açıkça belgelenmiştir ancak bashbu cümleye dikkat etmeniz gerektiğinde belgelerde bulunması zordur :

Subring genişletme işlemi gerçekleştirilmiyorsa, aşağıda belgelenen formları kullanarak bash, ayarlanmamış veya boş bir parametre için test eder. Kolonun çıkarılması, yalnızca ayarlanmamış bir parametre için bir teste neden olur .

Dolayısıyla ${1+"$@"}, "$@"yalnızca Bourne kabuğunun bu sınırlaması etrafında çalışan $1set ( $# > 0) olduğunda genişler .

Bourne kabuğunun bu problemi olan tek kabuk olduğuna dikkat edin. Modern shs (ki bu, Bourne kabuğunun olmayan) ( shPOSIX spesifikasyonuna uyan) uygun bir shsorunu yoktur. Bu nedenle, yalnızca /bin/shstandart bir kabuk yerine Bourne kabuğu olabilecek çok eski sistemlerde çalışmak için kodunuza ihtiyaç duymanız durumunda (POSIX’in standardın yerini belirtmediğini unutmayın, shörneğin Solaris 11’den önceki Solaris’de, /bin/shnormal / standart shbaşka bir yerde ( /usr/xpg4/bin/sh) iken, hala bir Bourne kabuğuydu (yine de belirli bir konuyu bulamamıştı ).

Bu perlrunperldoc sayfasında bir sorun var ancak bu $0alıntı değil.

Daha fazla bilgi için http://www.in-ulm.de/~mascheck/various/bourne_args/ adresini ziyaret edin .


Heirloom'da üremem. Muhtemelen Solaris için geçerli değildir.
ormaaj

2
@ormaaj. Evet, bağladığım sayfaya bakın. SVR3'te ve Solaris / SunOS'ta SVR4'te 5'in üzerinde yeniden kuruldu. Ve bu sayfa 4.1.x'in de sorunu olmadığını söylüyor.
Stéphane Chazelas

Ah, anlıyorum. <3 Mascheck sayfaları.
ormaaj

3

Arada bir fark var:

command ""

ve

command

Birinde, boş bir dize olan bir argüman geçiyorsunuz. İkincisi, geçen sıfır argüman vardır.

Her ikisi için "$ @" aynı şey eşit olacaktır: "". Ama kullanarak ${1:+"$@"}olacağını ""ilk ve niyet oldu saniye için geçirilen hiçbir argümanlar için.

Bu, isteğe bağlı bir komutla çağırdığınız veya etkileşimli bir kabuk elde etmek için herhangi bir argüman yoksa çağırdığınız sshwrapper adında aşağıdaki komut dosyasını yapıyorsanız önemlidir.

: sshwrapper [command]
exec /usr/bin/ssh "${HOSTNAME:-localhost}" "$@"

Bu, uzaktaki ana bilgisayarda "" çalıştırmayı dener (ki sadece döner), etkileşimli bir kabuk olmazdı.

: sshwrapper [command]
exec /usr/bin/ssh "${HOSTNAME:-localhost}" ${1:+"$@"}

Yürütücü, boş bir dize olarak değil, değişkeni doğru olarak yorumlayacağı için uzak ana bilgisayarda etkileşimli bir kabuk başlatır.

Bash manuel sayfalarında "$ {parametre: + kelime}" ("Alternatif Değer Kullanın") ve benzer değişken genişleme dizelerinin kullanımına bakın.


Bu, POSIX uyumlu herhangi bir uygulama için değil , yalnızca Bourne kabuğuna uygulanabilir gibi görünmektedir sh(diğer cevaba bakınız).
törzsmókus

4
Hayır, boş ${1:+"$@"}olsaydı argüman olmazdı $1. Sen istiyorsun ${1+"$@"}. Temelde onu tersine çevirdin.
Stéphane Chazelas

0

Stéphane Chazelas'ın cevabını özetledim:

  • $ 1 = null veya ayarlanmadığında $ {1: + "$ @"} 'testi
  • $ 1 ayarlanmadığında $ {1 + "$ @"} 'testi

bu yüzden "" parametresiyle ikinci olanı kullanırsanız, bu $ 1 değerinin boş olduğu, ancak null olup olmadığının test edilmediği anlamına gelir. , ancak "" ile $ {1: + "$ @"} 'kullanırsınız, $@daha fazla genişletilmez .


7
Bu kesinlikle özetlenebilir, ancak netleşmemiş olabilir ...
Archemar
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.