'$ @' versus comportamento '$ *' [duplicado]

0

O manual do bash diz:

Em relação a: $*

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.

Em relação a: $@

When the expansion occurs within double quotes, each parameter expands to a separate word. That is, "$@" is equivalent to "$1" "$2" ....

Desde que o primeiro caractere do valor da variável IFS seja de fato um único espaço, não consigo encontrar um exemplo em que esses dois parâmetros especiais produzam um comportamento diferente . Alguém pode me dar um exemplo (novamente, sem alterar IFS ) onde eles produziriam comportamentos diferentes?

Meu próprio teste, que ainda me deixa perplexo, é o seguinte:

#!/usr/bin/env bash
# File: test.sh
# set foo and bar in the global environment to $@ and $*

test_expansion () {
  foo="$@"
  bar="$*"
}

Agora testando:

. test.sh
test_expansion a b c d
# foo is $@
# bar is $*

for e in "$foo"; do
  echo "$e"
done
# a b c d

for e in "$bar"; do
  echo "$e"
done
# a b c d
    
por De Novo 26.11.2018 / 21:12

3 respostas

3

A diferença vem quando você tem argumentos que você passa na linha de comando com caracteres IFS neles (por exemplo, um argumento com um espaço). Para ver a diferença, veja este script:

#!/bin/bash

echo 'Here is $*'
for x in "$*"; do
    echo "  !${x}!"
done

echo ""
echo 'And here is $@'
for x in "$@"; do
    echo "  !${x}!"
done

exit 0

Agora, olhe a diferença quando você passa em um argumento com um espaço.

./testspace01.sh "This is" a test
Here is $*
  !This is a test!

And here is $@
  !This is!
  !a!
  !test!

Espero que isso ajude.

ATUALIZAÇÃO Ah, atribuir o que foi passado na linha de comando para uma variável traz suas próprias peculiaridades. :)

Lembre-se de que tudo que foi passado na linha de comando é uma matriz. Portanto, atribuir a matriz a uma string fornece algo diferente do que assinar em uma matriz. E, lidar com a matriz é diferente, dependendo se você estiver usando a estrela ou o asterisco. Aqui está uma versão atualizada do meu script.

#!/bin/bash

s_star="$*"
echo 'Here is s_star'
for x in "${s_star}"; do
    echo "  !${x}!"
done

a_star=("$*")
echo ""
echo 'Here is a_star'
for x in "${a_star}"; do
    echo "  !${x}!"
done

s_at="$@"
echo ""
echo 'Here is s_at'
for x in "${s_at}"; do
    echo "  !${x}!"
done

a_at=("$@")
echo ""
echo 'Here is a_at (using star)'
for x in "${a_at[*]}"; do
    echo "  !${x}!"
done

echo ""
echo 'Here is a_at (using at)'
for x in "${a_at[@]}"; do
    echo "  !${x}!"
done

exit 0

Aqui está a saída:

./testspace02.sh "This is" a test
Here is s_star
  !This is a test!

Here is a_star
  !This is a test!

Here is s_at
  !This is a test!

Here is a_at (using star)
  !This is a test!

Here is a_at (using at)
  !This is!
  !a!
  !test!

Como você pode ver, há diferentes comportamentos.

Espero que isso ajude a esclarecer as coisas ainda mais para você.

    
por 26.11.2018 / 21:22
3

Tente isto:

#!/bin/bash
show-difference () {
    for e in "$@" ; do
        printf '<%s>\n' "$e"
    done
    for e in "$*" ; do
        printf '[%s]\n' "$e"
    done
}

show-difference {a..h}

Saída:

<a>
<b>
<c>
<d>
<e>
<f>
<g>
<h>
[a b c d e f g h]

"$*" é uma única palavra, enquanto "$@" se expande para todos os parâmetros como palavras únicas. Além disso, "$@" funciona corretamente, mesmo se os argumentos contiverem o primeiro caractere do IFS.

    
por 26.11.2018 / 21:22
0
set -- "hello there" bumblebee

printf '%s\n' "$@"
printf '%s\n' "$*"

Resultado:

hello there
bumblebee

seguido por

hello there bumblebee

Isso mostra que "$@" gera uma lista de elementos citados individualmente, enquanto "$*" gera uma única string entre aspas.

    
por 26.11.2018 / 21:26