¿Qué significa $ {1 + "$ @"} en un script de shell y cómo se diferencia de "$ @"?


43

En la documentación de Perl, perlrun (1) sugiere iniciar scripts de Perl utilizando un shell bilingüe / encabezado de Perl:

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

Que ${1+"$@"}significa Intenté usar en su "$@"lugar (usando Bash como / bin / sh), y parece funcionar igual de bien.


Editar

Dos respuestas a continuación dicen que se supone que debe ser ${1:+"$@"}. Soy consciente de la ${parameter:+word}sintaxis ("Usar valor alternativo") documentada en bash (1). Sin embargo, no estoy convencido, porque

  1. Ambos ${1+"$@"}y "$@"funcionan bien, incluso cuando no hay parámetros. Si creo simple.sh como

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

    y question.sh como

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

    Puedo hacer que ambos trabajen de manera idéntica:

    $ ./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. También utilizan otras fuentes en Internet ${1+"$@"}, incluido un hacker que parece saber lo que está haciendo.

¿Quizás ${parameter+word}es una sintaxis alternativa (o obsoleta) no documentada ${parameter:+word}? ¿Alguien podría confirmar esa hipótesis?


Respuestas:


53

Eso es por compatibilidad con el shell Bourne. El shell Bourne era un antiguo shell que se lanzó por primera vez con la versión 7 de Unix en 1979 y aún era común hasta mediados de los 90 como /bin/shen la mayoría de los Unices comerciales.

Es el antepasado de la mayoría de las conchas tipo Bourneksh , basho zsh.

Tenía algunas características incómodas, muchas de las cuales se han reparado kshy las otras shells y la nueva especificación estándar de sh, una de las cuales es esta:

Con el shell Bourne (al menos aquellas variantes donde no se ha solucionado): se "$@"expande a un argumento vacío si la lista de parámetros posicionales está vacía ( $# == 0) en lugar de ningún argumento.

${var+something}se expande a "algo" a menos $varque no esté configurado. Está claramente documentado en todos los shells, pero es difícil de encontrar en la bashdocumentación, ya que debe prestar atención a esta oración:

Cuando no se realiza la expansión de subcadenas, utilizando los formularios documentados a continuación, bash prueba para un parámetro que no está establecido o es nulo. Omitir los dos puntos da como resultado una prueba solo para un parámetro que no está establecido .

Por lo tanto, se ${1+"$@"}expande "$@"solo si $1se establece ( $# > 0), lo que evita esa limitación del shell Bourne.

Tenga en cuenta que el shell Bourne es el único shell con ese problema. Los shs modernos (que se shajustan a la especificación POSIX de sh(que no es el shell Bourne)) no tienen ese problema. Por lo tanto, solo necesita eso si necesita que su código funcione en sistemas muy antiguos donde /bin/shpodría haber un shell Bourne en lugar de un shell estándar (tenga en cuenta que POSIX no especifica la ubicación del estándar sh, por ejemplo, en Solaris antes de Solaris 11, /bin/shtodavía era un shell Bourne (aunque no tenía ese problema en particular) mientras que el normal / estándar shestaba en otra ubicación ( /usr/xpg4/bin/sh)).

Sin embargo, hay un problema en esa perlrunpágina perldoc que $0no se cita.

Consulte http://www.in-ulm.de/~mascheck/various/bourne_args/ para obtener más información.


No se puede reproducir en la herencia. Probablemente no aplicable a Solaris.
ormaaj

2
@ormaaj. Sí, mira la página que he vinculado. Se arregló en SVR3, y Solaris / SunOS por encima de 5 rebase en SVR4. Y esa página menciona que 4.1.x tampoco tenía el problema.
Stéphane Chazelas

Ah, ya veo. <3 páginas de Mascheck.
ormaaj

3

Hay una diferencia entre:

command ""

y

command

En uno, está pasando un argumento que es una cadena vacía. En el segundo, se pasan cero argumentos.

Por tanto, "$ @" será igual a la misma cosa: "". Pero usar ${1:+"$@"}sería ""para el primero y no se aprobaron argumentos para el segundo, que era la intención.

Esto se vuelve importante si está haciendo algo en el siguiente script, llamado sshwrapper, al que llama con un comando opcional o sin argumentos para obtener un shell interactivo.

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

Esto intentaría ejecutar "" en el host remoto (que simplemente regresa), no sería un shell interactivo.

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

Comenzaría un shell interactivo en el host remoto porque el ejecutivo interpretaría correctamente la variable como nada, no como una cadena vacía.

Lea sobre el uso de "$ {parámetro: + palabra}" ("Usar valor alternativo") y cadenas de expansión variables similares en las páginas del manual de bash.


esto parece aplicarse solo a Bourne shell y no a ninguna shimplementación compatible con POSIX (ver otra respuesta).
törzsmókus

44
No, ${1:+"$@"}se expandiría a ningún argumento si $1estuviera vacío. Que desea ${1+"$@"}. Básicamente lo tienes invertido.
Stéphane Chazelas

0

Resumí la respuesta de Stéphane Chazelas:

  • $ {1: + "$ @"} 'prueba si $ 1 es nulo o sin establecer
  • $ {1 + "$ @"} 'prueba si $ 1 no está establecido

así que si usa el segundo con el parámetro "", eso significa que $ 1 es nulo, pero no prueba si es nulo o no, solo ve que ya se ha configurado, sin embargo, está vacío o no, por lo que expandirá $ @ , pero usa $ {1: + "$ @"} 'con "", ya no se expandirá $@.


77
Esto sin duda resume, a pesar de que podría no aclarar ...
Archemar
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.