Apa arti $ {1 + “$ @”} dalam skrip shell, dan apa bedanya dengan “$ @”?

43

Dalam dokumentasi Perl, perlrun (1) menyarankan meluncurkan skrip Perl menggunakan header bilingual shell / Perl:

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

Apa ${1+"$@"}artinya Saya mencoba menggunakan "$@"sebagai gantinya (menggunakan Bash sebagai / bin / sh), dan sepertinya berfungsi juga.


Sunting

Dua jawaban di bawah mengatakan bahwa memang seharusnya begitu ${1:+"$@"}. Saya mengetahui ${parameter:+word}sintaks ("Gunakan Nilai Alternatif") yang didokumentasikan dalam bash (1). Namun, saya tidak yakin, karena

  1. Keduanya ${1+"$@"}dan "$@"berfungsi dengan baik, bahkan ketika tidak ada parameter. Jika saya membuat simple.sh sebagai

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

    dan question.sh sebagai

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

    Saya bisa membuat keduanya bekerja secara identik:

    $ ./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. Sumber lain di Internet juga menggunakan ${1+"$@"}, termasuk satu peretas yang tampaknya tahu apa yang dia lakukan.

Mungkin ${parameter+word}sintaks alternatif (atau tidak digunakan) yang tidak didokumentasikan ${parameter:+word}? Bisakah seseorang mengkonfirmasi hipotesis itu?

200_sukses
sumber
Sepertinya grawlix
Martin Thoma

Jawaban:

53

Itu untuk kompatibilitas dengan shell Bourne. Cangkang Bourne adalah cangkang tua yang pertama kali dirilis dengan Unix versi 7 pada tahun 1979 dan masih umum sampai pertengahan 90-an seperti /bin/shpada kebanyakan Unix komersial.

Ini adalah leluhur dari sebagian besar kerang mirip Bourne seperti ksh, bashatau zsh.

Itu memiliki beberapa fitur canggung banyak yang telah diperbaiki kshdan kerang lainnya dan spesifikasi standar baru sh, salah satunya adalah ini:

Dengan shell Bourne (setidaknya varian yang belum diperbaiki): "$@"perluas satu argumen kosong jika daftar parameter posisi kosong ( $# == 0) alih-alih tidak ada argumen sama sekali.

${var+something}meluas ke "sesuatu" kecuali $vartidak disetel. Itu jelas didokumentasikan dalam semua shell tetapi sulit ditemukan dalam bashdokumentasi karena Anda perlu memperhatikan kalimat ini:

Saat tidak melakukan ekspansi substring, menggunakan formulir yang didokumentasikan di bawah ini, uji bash untuk parameter yang tidak disetel atau nol. Menghilangkan titik dua menghasilkan tes hanya untuk parameter yang tidak disetel .

Jadi ${1+"$@"}mengembang "$@"hanya jika $1diatur ( $# > 0) yang bekerja di sekitar batasan shell Bourne.

Perhatikan bahwa cangkang Bourne adalah satu-satunya cangkang dengan masalah itu. Modern sh(yang shsesuai dengan spesifikasi POSIX sh(yang tidak dimiliki shell Bourne)) tidak memiliki masalah itu. Jadi Anda hanya perlu itu jika Anda memerlukan kode Anda untuk bekerja pada sistem yang sangat lama di mana /bin/shmungkin shell Bourne bukan shell standar (perhatikan bahwa POSIX tidak menentukan lokasi standar sh, jadi misalnya pada Solaris sebelum Solaris 11, /bin/shmasih merupakan shell Bourne (meskipun tidak memiliki masalah tertentu) sementara yang normal / standar shberada di lokasi lain ( /usr/xpg4/bin/sh)).

Namun ada masalah di perlrunhalaman perldoc yang $0tidak dikutip.

Lihat http://www.in-ulm.de/~mascheck/various/bourne_args/ untuk informasi lebih lanjut.

Stéphane Chazelas
sumber
Tidak dapat bereproduksi dalam Heirloom. Mungkin tidak berlaku untuk Solaris.
ormaaj
2
@ormaaj. Ya, lihat halaman yang saya tautkan. Itu diperbaiki di SVR3, Dan Solaris / SunOS di atas 5 rebased pada SVR4. Dan halaman itu menyebutkan bahwa 4.1.x tidak memiliki masalah juga.
Stéphane Chazelas
Ah saya mengerti. <3 halaman Mascheck.
ormaaj
3

Ada perbedaan antara:

command ""

dan

command

Dalam satu, Anda melewati satu argumen yang merupakan string kosong. Dalam yang kedua, ada nol argumen yang disahkan.

Untuk kedua, "$ @" akan sama dengan hal yang sama: "". Tetapi menggunakan ${1:+"$@"}akan ""untuk yang pertama dan tidak ada argumen yang berlalu untuk yang kedua, yang merupakan maksud.

Ini menjadi penting jika Anda melakukan sesuatu skrip di bawah ini, yang disebut sshwrapper, yang Anda panggil dengan perintah opsional atau tanpa argumen untuk mendapatkan shell interaktif.

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

Ini akan mencoba menjalankan "" pada host jarak jauh (yang baru saja mengembalikan), itu tidak akan menjadi shell interaktif.

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

Akan memulai shell interaktif pada host jarak jauh karena exec akan benar menafsirkan variabel sebagai bukan apa-apa, bukan string kosong.

Baca penggunaan "$ {parameter: + word}" ("Gunakan Nilai Alternatif") dan string ekspansi variabel serupa di halaman manual bash.

Arcege
sumber
ini tampaknya hanya berlaku untuk Bourne shell dan bukan untuk shimplementasi POSIX-conformant (lihat jawaban lain).
törzsmókus
4
Tidak, ${1:+"$@"}akan diperluas ke tidak ada argumen jika $1kosong. Kamu ingin ${1+"$@"}. Pada dasarnya Anda memilikinya terbalik.
Stéphane Chazelas
0

Saya merangkum jawaban Stéphane Chazelas:

  • $ $ 1: + "$ @"} 'menguji apakah $ 1 null atau tidak disetel
  • Tes $ {1 + "$ @"} 'jika $ 1 tidak disetel

jadi jika menggunakan yang kedua dengan parameter "", itu berarti $ 1 adalah nol, tetapi itu tidak menguji apakah itu nol atau tidak, itu hanya melihat itu sudah diatur tetapi tetap kosong atau tidak, sehingga akan memperluas $ @ , tetapi Anda menggunakan $ {1: + "$ @"} 'dengan "", itu tidak akan berkembang $@lagi.

Kevin
sumber
7
Ini tentu saja dirangkum, meskipun mungkin tidak menjelaskan ...
Archemar