Qual é o propósito de ter duas variáveis ($ @, $ *) para transmitir os argumentos de um comando para um script? [duplicado]

7

Li sobre as variáveis especiais usadas em um script $@ e $* . Tanto quanto eu entendo, os argumentos usados durante a execução do script são armazenados em duas variáveis especiais, uma vez que todos os argumentos em $@ e uma vez todos os argumentos em $* , assim eles podem ser acessados dentro do script.

Eu não entendo porque deve haver duas variáveis especiais para o mesmo conjunto de argumentos. Qual é a diferença, quando é aquela e quando a outra variável especial é usada?

    
por Abdul Al Hazred 21.02.2015 / 14:41

7 respostas

3

A explicação primitiva simples é:

  • $* all set arguments é uma string (os argumentos são separados pelo primeiro caractere em $IFS )
  • $@ cada argumento é uma string diferente (os argumentos são separados por nova linha)

De man bash :

* Expands to the positional parameters, starting from one.  When the expansion is not within  dou‐
  ble  quotes, each positional parameter expands to a separate word.  In contexts where it is per‐
  formed, those words are subject to further word splitting  and  pathname  expansion.   When  the
  expansion occurs within double quotes, it expands to a single word with the value of each param‐
  eter separated by the first character of the IFS special variable.  That is, "$*" is  equivalent
  to  "$1c$2c...",  where  c  is  the first character of the value of the IFS variable.  If IFS is
  unset, the parameters are separated by spaces.  If IFS is null, the parameters are joined  with‐
  out intervening separators.
@ Expands  to the positional parameters, starting from one.  When the expansion occurs within dou‐
  ble quotes, each parameter expands to a separate word.  That is, "$@" is equivalent to "$1" "$2"
  ...   If  the double-quoted expansion occurs within a word, the expansion of the first parameter
  is joined with the beginning part of the original word, and the expansion of the last  parameter
  is  joined  with  the  last part of the original word.  When there are no positional parameters,
  "$@" and $@ expand to nothing (i.e., they are removed).
    
por 21.02.2015 / 14:52
1

Entre outras coisas:

  • "$*" se expande para "arg1 arg2 arg3 …"
  • "$@" se expande para "arg1" "arg2" "arg3" …

Assim, "$@" é mais seguro. $* pode ser mais antigo, existindo para compatibilidade com versões anteriores.

    
por 21.02.2015 / 14:54
1

De man bash :

Special Parameters
   The  shell treats several parameters specially.  These parameters may only
   be referenced; assignment to them is not allowed.
   *      Expands to the positional parameters, starting from one.  When  the
          expansion  is  not  within double quotes, each positional parameter
          expands to a separate word.  In contexts  where  it  is  performed,
          those  words  are  subject  to  further word splitting and pathname
          expansion.  When the expansion  occurs  within  double  quotes,  it
          expands to a single word with the value of each parameter separated
          by the first character of the IFS special variable.  That is,  "$*"
          is equivalent to "$1c$2c...", where c is the first character of the
          value of the IFS variable.  If IFS is  unset,  the  parameters  are
          separated  by  spaces.   If  IFS is null, the parameters are joined
          without intervening separators.
   @      Expands to the positional parameters, starting from one.  When  the
          expansion  occurs within double quotes, each parameter expands to a
          separate word.  That is, "$@" is equivalent to "$1"  "$2"  ...   If
          the  double-quoted expansion occurs within a word, the expansion of
          the first parameter is joined with the beginning part of the origi‐
          nal  word,  and  the expansion of the last parameter is joined with
          the last part of the original word.  When there are  no  positional
          parameters, "$@" and $@ expand to nothing (i.e., they are removed).

Compare esses quatro casos, especialmente com espaços contendo argumentos.

for i in $*; do echo "$i"; done
for i in $@; do echo "$i"; done
for i in "$*"; do echo "$i"; done
for i in "$@"; do echo "$i"; done
    
por 21.02.2015 / 15:08
1

A diferença está na maneira como as duas variáveis são expandidas.

$@ expande para que cada argumento seja separado por foo arg1 arg2 arg3NUL e seja visto individualmente. Assim, dado $@ , arg1arg1arg2foo bararg3 se tornará foo bar . Em particular, cada argumento é protegido da divisão, de modo que, se foo for bar , a menos que outro processamento seja feito, ele será visto como $* e não IFS e IFS separadamente.

$* se expande para que cada argumento seja separado pelo primeiro caractere de $@ , o Separador de campo interno. O IFS=: padrão tem espaço como seu primeiro caractere, portanto, a expansão de $* geralmente é igual à de arg1:arg2:arg3 . No entanto, se eu definir, digamos, %code% , então %code% expandirá para %code% .

O uso que você coloca depende da situação. Por exemplo, aqui está um truque para obter rapidamente uma soma de muitos números:

sum () (
IFS=+
echo $(( $* ))
)

Então:

$ sum 1 2 3
6

Esse truque é, obviamente, muito frágil.

    
por 21.02.2015 / 14:49
0

Parâmetros especiais $ * e $ @:

Existem parâmetros especiais que permitem acessar todos os argumentos da linha de comando de uma só vez. $ * e $ @ ambos irão agir da mesma forma, a menos que estejam entre aspas duplas, "".

O parâmetro especifica todos os argumentos de linha de comando, mas o parâmetro especial "$ *" usa a lista inteira como um argumento com espaços entre e o parâmetro especial "$ @" pega a lista inteira e a separa em argumentos separados. / p>

Podemos escrever o script de shell para processar um número desconhecido de argumentos de linha de comando com os parâmetros especiais $ * ou $ @:

    
por 21.02.2015 / 14:54
0

Isso é tudo sobre como os separadores de argumentos (por espaços padrão) são manipulados:

"$@" expandirá para uma seqüência de strings, enquanto "$*" será expandido para uma única string.

Pegue o script de exemplo "test.sh" abaixo:

#$/bin/sh

for i in "$*"; do
  echo $i
done

echo "===="

for i in "$@"; do
  echo $i
done

Quando chamado com 4 args chamado assim: ./test.sh 1 2 3 "4 5" , terá a seguinte saída:

1 2 3 4 5
====
1
2
3
4 5
    
por 21.02.2015 / 14:52
0

Os parâmetros especiais "$*" e "$@" referem-se a todos os argumentos no array de argumento do shell de maneiras diferentes.

  • "$@" - este parâmetro é como você se refere ao array shell como uma lista de strings. Com isso, você pode expandir uma reprodução fiel da matriz de argumentos para entregar a outro comando. A expansão de "$@" também pode ser adicionada em uma das extremidades, prefixando ou fixando strings.

  • "$*" - este parâmetro é como você se refere a toda a matriz como uma única cadeia concatenada no primeiro caractere no valor do parâmetro shell $IFS special. Com isso, você pode serializar seu array de argumentos ou transformá-lo em diferentes delimitadores.

Ambos os parâmetros são POSIX portáveis, mas seus atributos não são exclusivos da matriz de argumentos. Em praticamente todos os shell que também implementam matrizes nomeadas - como bash ' ${array[@]} ' - suas funções são transferidas. Portanto, "${array[*]}" tem os mesmos laços com $IFS do que "$*" e "${array[@]}" reproduz suas sequências constituintes tão fielmente quanto "$@" .

"$@" e "$*" são inicialmente preenchidos pelos argumentos do shell (ou uma função / .dot script) , mas essa não é a única maneira de set deles.

set 1 2 3 ''
for n do IFS=$((n-1))
    set "$*" "$@$3"
done
printf '<%s>\n' "$@"

OUTPUT

<102030111213132102030212223232-10203011121313-102030-1-2-3-321>
<102030111213132102030212223232>
<10203011121313>
<102030>
<1>
<2>
<3>
<321102030>
    
por 21.02.2015 / 16:59