De acordo com as Leis 12.965/2014 e 13.709/2018, que regulam o uso da Internet e o tratamento de dados pessoais no Brasil, ao me inscrever na newsletter do portal DICAS-L, autorizo o envio de notificações por e-mail ou outros meios e declaro estar ciente e concordar com seus Termos de Uso e Política de Privacidade.

"$@" e "$*" no Shell Linux: entenda de uma vez a diferença

Colaboração: Rubens Queiroz de Almeida

Data de Publicação: 14 de agosto de 2026

Quem começa a criar scripts em Shell logo encontra duas variáveis especiais aparentemente muito parecidas: $@ e $*. Ambas representam os argumentos passados para um script ou uma função, mas existe uma diferença importante entre elas, especialmente quando são utilizadas entre aspas.

Compreender essa diferença evita problemas com argumentos que contêm espaços e ajuda a escrever scripts mais seguros e confiáveis.

Os parâmetros posicionais

Considere um script chamado argumentos.sh, executado da seguinte forma:

$ ./argumentos.sh "João da Silva" "São Paulo" 30 

O Shell recebe três argumentos e os armazena nos chamados parâmetros posicionais:

$1 = João da Silva
$2 = São Paulo
$3 = 30

A variável especial $# informa quantos argumentos foram recebidos:

 printf 'Foram recebidos %d argumentos.\n' "$#" 

Nesse exemplo, o valor de $# será 3.

Tanto $@ quanto $* representam o conjunto desses parâmetros posicionais. A diferença aparece na maneira como os argumentos são expandidos pelo Shell.

Como funciona "$@"

Quando $@ é utilizado entre aspas ("$@") cada parâmetro posicional é preservado como um argumento independente. Conceitualmente, podemos representar essa expansão da seguinte maneira:

"$@" = "$1" "$2" "$3" ...  

No exemplo anterior, "$@" representa três argumentos:

João da Silva
São Paulo
30

Embora os dois primeiros contenham espaços, eles continuam sendo tratados como unidades completas.

Podemos verificar isso com o seguinte script:

#!/bin/bash

for argumento in "$@"; do
    printf '<%s>\n' "$argumento"
done

Ao executar:

$ ./argumentos.sh "João da Silva" "São Paulo" 30 

teremos:

<João da Silva>
<São Paulo>
<30>

O comando for executou três vezes, uma para cada argumento recebido.

Como funciona "$*"

Quando $* é utilizado entre aspas: "$*" todos os parâmetros posicionais são reunidos em uma única string. Conceitualmente, podemos representar essa expansão assim:

 "$*" = "$1 $2 $3 ..." 

A separação entre os valores é feita pelo primeiro caractere da variável especial IFS. Por padrão, esse caractere geralmente é um espaço.

Usando o mesmo exemplo:

#!/bin/bash

for argumento in "$*"; do
    printf '<%s>\n' "$argumento"
done

A execução produzirá:

<João da Silva São Paulo 30>

Dessa vez, o for executou apenas uma vez, pois "$*" gerou uma única string contendo todos os argumentos.

A diferença principal pode ser resumida desta forma:

"$@" → "$1" "$2" "$3"
"$*" → "$1 $2 $3"

Alterando o separador usado por "$*"

Como "$*" utiliza o primeiro caractere de IFS para separar os parâmetros, podemos definir outro separador.

Para unir os argumentos com o caractere ^, por exemplo, podemos escrever:

#!/bin/bash

IFS='^'
printf '%s\n' "$*"

Executando:

$ ./argumentos.sh "João da Silva" "São Paulo" 30 

o resultado será:

João da Silva^São Paulo^30

Observe que o separador aparece somente entre os argumentos:

 "$1^$2^$3" 

Caso também seja necessário colocar um ^ no início da saída, ele deverá ser acrescentado explicitamente:

IFS='^'
printf '^%s\n' "$*"

O resultado será:

^João da Silva^São Paulo^30

Em scripts maiores, é recomendável evitar alterações globais em IFS. Podemos restringir a mudança ao ambiente de um subshell:

(
    IFS='^'
    printf '%s\n' "$*"
)

Dessa forma, o valor original de IFS será preservado no restante do script.

Comparando "$@" e "$*" na prática

O script a seguir mostra claramente a diferença:

#!/bin/bash

printf 'Quantidade recebida: %d\n\n' "$#"

printf 'Percorrendo "$@":\n'

for argumento in "$@"; do
    printf '<%s>\n' "$argumento"
done

printf '\nPercorrendo "$*":\n'

for argumento in "$*"; do
    printf '<%s>\n' "$argumento"
done

Executando:

$ ./argumentos.sh "João da Silva" "São Paulo" 30
Quantidade recebida: 3

Percorrendo "$@":
<João da Silva>
<São Paulo>
<30>

Percorrendo "$*":
<João da Silva São Paulo 30>

Com "$@", cada argumento mantém sua identidade. Com "$*", todos os argumentos são transformados em uma única string.

O que acontece quando não usamos aspas?

Também é possível escrever:

 $@ 

ou:

 $* 

Porém, essas formas devem ser evitadas na maioria das situações. Sem as aspas, o Shell pode aplicar novamente a separação de palavras e a expansão de nomes de arquivos.

Considere este exemplo:

#!/bin/bash

for argumento in $@; do
    printf '<%s>\n' "$argumento"
done

Ao executar:

$ ./argumentos.sh "João da Silva" "São Paulo" 30

<João>
<da>
<Silva>
<São>
<Paulo>
<30>

Os três argumentos originais foram divididos em seis palavras. As informações sobre os limites de cada argumento foram perdidas.

A ausência de aspas também pode produzir resultados inesperados quando os argumentos contêm curingas como *, ? e [. Esses caracteres podem ser interpretados pelo Shell como padrões para localizar nomes de arquivos no diretório atual.

Por exemplo:

 ./argumentos.sh "*.txt" 

Se o script utilizar $@ sem aspas, o padrão poderá ser expandido para os nomes dos arquivos com extensão .txt. Se utilizar "$@", o texto *.txt será preservado exatamente como foi recebido.

Repassando argumentos para outro comando

Um dos usos mais comuns de "$@" é repassar para outro comando todos os argumentos recebidos por um script.

Considere este pequeno script:

#!/bin/bash ls "$@" 

Se ele for executado assim:

$ ./listar.sh -l "Meus Documentos"

a linha:

 ls "$@" 

será equivalente a:

 ls "-l" "Meus Documentos" 

O diretório Meus Documentos continuará sendo um único argumento, apesar do espaço em seu nome.

Se fosse utilizado "$*":

 ls "$*" 

o comando ls receberia um único argumento:

-l Meus Documentos

Nesse caso, a opção -l deixaria de ser reconhecida como uma opção independente.

Por essa razão, "$@" é quase sempre a escolha correta quando desejamos transferir os argumentos de um script ou função para outro comando.

Uma forma de visualizar a diferença

Imagine que um script recebeu três caixas:

 [João da Silva] [São Paulo] [30] 

A expansão "$@" entrega as três caixas separadamente:

 [João da Silva] [São Paulo] [30] 

A expansão "$*" coloca todo o conteúdo em uma única caixa:

 [João da Silva São Paulo 30] 

Essa é a essência da diferença. "$@" preserva a estrutura original dos argumentos, enquanto "$*" os combina em um único texto.

Regra prática

Na maioria dos scripts, a forma recomendada é:

 "$@" 

Ela mantém cada argumento separado e preserva corretamente os espaços e outros caracteres presentes nos valores.

Use "$*" quando houver uma necessidade específica de juntar todos os parâmetros em uma única string, possivelmente utilizando um separador definido por IFS.

A regra pode ser resumida assim:

"$@"   # todos os argumentos, cada um preservado separadamente
"$*"   # todos os argumentos reunidos em uma única string

Na dúvida, use "$@". Essa escolha costuma corresponder ao comportamento esperado e evita grande parte dos erros relacionados ao tratamento de argumentos em scripts Shell.



Veja a relação completa dos artigos de Rubens Queiroz de Almeida