O que $ @ significa em um script de shell?

Respostas:

243

$@são todos os parâmetros passados ​​para o script.

Por exemplo, se você ligar ./someScript.sh foo bar, $@será igual a foo bar.

Se você fizer:

./someScript.sh foo bar

e depois dentro de someScript.shreferência:

umbrella_corp_options "$@"

isso será passado para umbrella_corp_optionscada parâmetro individual entre aspas duplas, permitindo pegar parâmetros com espaço em branco do chamador e transmiti-los.

Har
fonte
1
O que $ @ conteria se eu fizesse someScript.sh foo bar "boo far"?
trusktr
7
$ @ é especial se estiver escrito entre aspas duplas. Em seguida, resultará em uma lista de valores citados, no seu caso, trusktr, nos três argumentos "foo", "bar" e "vaia longe".
Alfe
4
Embora seja geralmente o caso, $@que não necessariamente vir de paramaters passados para o script ... eg; set a b "x   y"; printf '(%s)' "$@"saídas(a)(b)(x   y)
Peter.O
I como a resposta de Alfe melhor, porque ele dá a diferença principal entre $@e$*
donleyp
106

$@é quase o mesmo que $*, ambos significando "todos os argumentos da linha de comando". Eles geralmente são usados ​​para simplesmente passar todos os argumentos para outro programa (formando um invólucro em torno desse outro programa).

A diferença entre as duas sintaxes aparece quando você tem um argumento com espaços (por exemplo) e coloca $@aspas duplas:

wrappedProgram "$@"
# ^^^ this is correct and will hand over all arguments in the way
#     we received them, i. e. as several arguments, each of them
#     containing all the spaces and other uglinesses they have.
wrappedProgram "$*"
# ^^^ this will hand over exactly one argument, containing all
#     original arguments, separated by single spaces.
wrappedProgram $*
# ^^^ this will join all arguments by single spaces as well and
#     will then split the string as the shell does on the command
#     line, thus it will split an argument containing spaces into
#     several arguments.

Exemplo: Chamando

wrapper "one two    three" four five "six seven"

vai resultar em:

"$@": wrappedProgram "one two    three" four five "six seven"
"$*": wrappedProgram "one two    three four five six seven"
                             ^^^^ These spaces are part of the first
                                  argument and are not changed.
$*:   wrappedProgram one two three four five six seven
Alfe
fonte
2
Eles não são os mesmos, e a página de manual é clara sobre os efeitos colaterais de $ * usando o IFS - o que não é necessariamente espaço. (Se eles eram os mesmos, não haveria qualquer ponto, diferente de compatibilidade talvez, na oferta de ambos.)
Jorgensen
6
Não, eles não são. E eu disse duas linhas abaixo: "A diferença entre os dois ..." Para obter sentenças curtas e aumentar a legibilidade, o leitor precisa ler mais de uma sentença antes de emitir um veredicto: - /
Alfe
2
Além disso, a inserção de Christoffer dessa única palavra "quase" fez uma enorme diferença, sem sacrificar a concisão ou a legibilidade. Na verdade, eu votei positivamente nesta resposta (em oposição à aceita) exatamente devido à ênfase sutil da diferença ... - antes de perceber que era quase contra a sua vontade! ;)
Sz.
Acho que essa palavra fez muita diferença para as pessoas que deram um veredicto logo após ler a primeira frase ;-) e nunca foi contra a minha vontade. Eu realmente gostaria de escrever também para essas pessoas.
Alfe 02/03
Muito claro. wrappedProgram "$*"-> separated by single spaces.mas no seu segundo exemplo, eles não são separados por espaços únicos.
Felix Dombek #
36

Estes são os argumentos da linha de comando em que:

$@= armazena todos os argumentos em uma lista de cadeias
$*= armazena todos os argumentos como uma única cadeia
$#= armazena o número de argumentos

Sameer Duwal
fonte
(A imprecisão acima mencionado por @iruvar foi fixado.)
Mateen Ulhaq
13

O uso de $@meios puros na maioria dos casos "prejudica o programador o máximo possível", porque na maioria dos casos isso leva a problemas com a separação de palavras e com espaços e outros caracteres nos argumentos.

Em (adivinhado) 99% de todos os casos, é necessário incluí-lo em ": "$@"é o que pode ser usado para iterar de maneira confiável os argumentos.

for a in "$@"; do something_with "$a"; done
glglgl
fonte
4
Sua linha pode ser escrita como: para a; faça algo_com "$ a"; done ;-)
Alfe
1
@ Eu sei, apenas esqueci. Pense nisso como for a in start_token "$@" end_token; do something_with "$a"; done:-)
glglgl
9

Do manual:

@

Expande para os parâmetros posicionais, iniciando em um. Quando a expansão ocorre entre aspas duplas, cada parâmetro se expande para uma palavra separada. Ou seja, "$ @" é equivalente a "$ 1" "$ 2" .... Se a expansão de aspas duplas ocorrer em uma palavra, a expansão do primeiro parâmetro será associada à parte inicial da palavra original e o valor a expansão do último parâmetro é associada à última parte da palavra original. Quando não há parâmetros posicionais, "$ @" e $ @ expandem para nada (ou seja, eles são removidos).

Christoffer Hammarström
fonte
1

Significado.

Em resumo, $@expande para os argumentos posicionais passados ​​do chamador para uma função ou um script . Seu significado é dependente do contexto : dentro de uma função, ele se expande para os argumentos passados ​​para essa função. Se usado em um script (não dentro do escopo de uma função), ele se expande para os argumentos passados ​​para esse script.

$ cat my-sh
#! /bin/sh
echo "$@"

$ ./my-sh "Hi!"
Hi!
$ put () ( echo "$@" )
$ put "Hi!"
Hi!

Divisão de palavras.

Agora, outro tópico que é de suma importância ao entender como $@se comporta no shell é a divisão de palavras . O shell divide os tokens com base no conteúdo da IFSvariável. Seu valor padrão é \t\n; ou seja, espaço em branco, guia e nova linha.

A expansão "$@"fornece uma cópia original dos argumentos transmitidos. No entanto, a expansão $@nem sempre será. Mais especificamente, se os argumentos contiverem caracteres de IFS, eles serão divididos.


Na maioria das vezes o que você deseja usar é "$@", não $@.

Luis Lavaire
fonte