$ {1 + phiên bản $ @ Biệt} có nghĩa là gì trong tập lệnh shell và nó khác với tập tin $ @ @ như thế nào?


43

Trong tài liệu Perl, perlrun (1) đề xuất khởi chạy các tập lệnh Perl bằng cách sử dụng tiêu đề shell / Perl song ngữ:

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

${1+"$@"}nghĩa là gì? Tôi đã thử sử dụng "$@"thay thế (sử dụng Bash as / bin / sh) và dường như nó cũng hoạt động tốt.


Biên tập

Hai câu trả lời dưới đây nói rằng nó được cho là như vậy ${1:+"$@"}. Tôi biết ${parameter:+word}cú pháp ("Sử dụng giá trị thay thế") được ghi lại trong bash (1). Tuy nhiên, tôi không tin, bởi vì

  1. Cả hai ${1+"$@"}"$@"hoạt động tốt, ngay cả khi không có tham số. Nếu tôi tạo Simple.sh như

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

    và question.sh như

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

    Tôi có thể khiến cả hai làm việc giống hệt nhau:

    $ ./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. Các nguồn khác trên Internet cũng sử dụng ${1+"$@"}, bao gồm một hacker dường như biết anh ta đang làm gì.

Có lẽ ${parameter+word}là một cú pháp thay thế (hoặc không dùng nữa) không có giấy tờ cho ${parameter:+word}? Ai đó có thể xác nhận giả thuyết đó?


Trông giống như grawlixes
Martin Thoma

Câu trả lời:


53

Đó là khả năng tương thích với vỏ Bourne. Shell Bourne là một vỏ cũ được phát hành lần đầu tiên với phiên bản Unix 7 vào năm 1979 và vẫn còn phổ biến cho đến giữa thập niên 90 như /bin/shtrên hầu hết các Unices thương mại.

Nó là tổ tiên của hầu hết các vỏ giống như Bourneksh , bashhay zsh.

Nó có một vài tính năng khó xử mà nhiều tính năng đã được sửa chữa kshvà các vỏ khác và đặc điểm kỹ thuật tiêu chuẩn mới của sh, một trong số đó là:

Với shell Bourne (ít nhất là các biến thể không được sửa): "$@"mở rộng thành một đối số trống nếu danh sách các tham số vị trí trống ( $# == 0) thay vì không có đối số nào.

${var+something}mở rộng thành "một cái gì đó" trừ khi không $varđược đặt. Nó được ghi lại rõ ràng trong tất cả các shell nhưng khó tìm thấy trong bashtài liệu vì bạn cần chú ý đến câu này:

Khi không thực hiện mở rộng chuỗi con, sử dụng các biểu mẫu được ghi lại dưới đây, bash kiểm tra tham số không được đặt hoặc null. Bỏ qua các kết quả dấu hai chấm trong một thử nghiệm chỉ cho một tham số không được đặt .

Vì vậy, ${1+"$@"}mở rộng thành "$@"chỉ khi $1được đặt ( $# > 0) hoạt động xung quanh giới hạn đó của vỏ Bourne.

Lưu ý rằng vỏ Bourne là vỏ duy nhất có vấn đề đó. Các hiện đại sh( shphù hợp với đặc điểm kỹ thuật POSIX của sh(mà vỏ Bourne không phải)) không có vấn đề đó. Vì vậy, bạn chỉ cần rằng nếu bạn cần mã của mình để hoạt động trên các hệ thống rất cũ, nơi /bin/shcó thể là vỏ Bourne thay vì vỏ tiêu chuẩn (lưu ý rằng POSIX không chỉ định vị trí của tiêu chuẩn sh, ví dụ như trên Solaris trước Solaris 11, /bin/shvẫn là một vỏ Bourne (mặc dù không có vấn đề cụ thể đó) trong khi bình thường / tiêu chuẩn shở một vị trí khác ( /usr/xpg4/bin/sh)).

Có một vấn đề trong perlruntrang perldoc trong đó $0không được trích dẫn mặc dù.

Xem http://www.in-ulm.de/~mascheck/various/bourne_args/ để biết thêm thông tin.


Không thể sinh sản trong Gia truyền. Có lẽ không áp dụng cho Solaris.
ormaaj

2
@ormaaj. Vâng, xem trang tôi liên kết. Nó đã được sửa trong SVR3 và Solaris / SunOS trên 5 đã phản công trên SVR4. Và trang đó đề cập rằng 4.1.x cũng không có vấn đề.
Stéphane Chazelas

Ah tôi thấy. <3 trang Mascheck.
ormaaj

3

Có một sự khác biệt giữa:

command ""

command

Trong một, bạn đang truyền một đối số là một chuỗi rỗng. Trong lần thứ hai, không có đối số nào được thông qua.

Đối với cả hai, "$ @" sẽ tương đương với cùng một điều : "". Nhưng sử dụng ${1:+"$@"}sẽ là ""cho lần đầu tiên và không có đối số nào được thông qua cho lần thứ hai, đó là ý định.

Điều này trở nên quan trọng nếu bạn đang thực hiện một cái gì đó theo kịch bản bên dưới, được gọi là sshwrapper, mà bạn gọi bằng một lệnh tùy chọn hoặc không có đối số để có được vỏ tương tác.

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

Điều này sẽ cố chạy "" trên máy chủ từ xa (chỉ trả về), nó sẽ không phải là một vỏ tương tác.

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

Sẽ bắt đầu một vỏ tương tác trên máy chủ từ xa vì người thực thi sẽ hiểu chính xác biến là không có gì, không phải là một chuỗi rỗng.

Đọc về cách sử dụng "$ {tham số: + word}" ("Sử dụng giá trị thay thế") và các chuỗi mở rộng biến tương tự trong các trang hướng dẫn bash.


điều này dường như chỉ áp dụng cho shell Bourne và không áp dụng cho bất kỳ shtriển khai tuân thủ POSIX nào (xem câu trả lời khác).
törzsmókus 7/1/2015

4
Không, ${1:+"$@"}sẽ mở rộng thành không có đối số nếu $1trống. Bạn muốn ${1+"$@"}. Về cơ bản bạn có nó đảo ngược.
Stéphane Chazelas

0

Tôi đã tóm tắt câu trả lời của Stéphane Chazelas:

  • Kiểm tra $ {1: + "$ @"} 'nếu $ 1 null hoặc không được đặt
  • Kiểm tra $ {1 + "$ @"} 'nếu bỏ đặt $ 1

Vì vậy, nếu sử dụng cái thứ hai với tham số "", điều đó có nghĩa là $ 1 là null, nhưng nó không kiểm tra xem nó có null hay không, nó chỉ thấy nó đã được xử lý tuy nhiên nó trống hay chưa, vì vậy nó sẽ mở rộng $ @ , nhưng bạn sử dụng $ {1: + "$ @"} 'với "", nó sẽ không mở rộng $@thêm nữa.


7
Điều này chắc chắn được tóm tắt, mặc dù nó có thể không làm rõ ...
Archemar 11/03/2015
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.