Iterar através de argumentos de linha de comando no Bash

1

Alguém pode explicar a diferença entre esses dois blocos de código? Eu pensaria que o Bloco 2 produziria o mesmo que o Bloco 1, mas isso não acontece. Alguém pode explicar por quê?

# ./arguments.sh hello my name is X

Bloco 1

for i
do
    echo $i
done

Saída:

hello
my
name
is
X

Bloco nº 2

args=$#
for (( i=1; i<=$args; i+=1 ))
do
    echo $i
done

Saída:

1
2
3
4
5
    
por jes516 02.01.2016 / 22:17

2 respostas

3

a resposta de roaima responde à pergunta que você fez:

Q: What is the difference between these two code blocks?  Why do they give different output?

A: The first loop is iterating over the command line arguments; the second one is iterating over the argument numbers (indices).

... embora eu presuma que você teria imaginado por si mesmo em outros seis a oito minutos - é meio óbvio. Você provavelmente quer que o segundo programa faça algo como

echo $$i                                        # This doesn't do what you want.

para exibir o argumento indexado pelo número que é armazenado na variável i (e referenciada como $i ). Como observado no comentário, isso não faz o que você quer. ( faz fazer alguma coisa; Encorajo-vos a experimentar e descobrir o que faz.) Mas isso está perto de algo que funciona:

eval echo \$$i                                  # Don't do this.

ou, equivalentemente,

eval echo '$'"$i"                               # Don't do this.

Estes comandos

  • obtenha o valor de i (um dos números 1, 2, 3, ...)
  • coloque um $ na frente dele, formando $1 , $2 , $3 , etc.
  • use o comando eval para dizer "pegue esta linha de comando que eu acabei de construir, e eval uate como se eu tivesse digitado.

Então, isso teria o efeito de executar

echo $1
echo $2
echo $3
   ︙

Mas, como os comentários sugerem, você deve tentar evitar isso. eval pode ser perigoso se a entrada for outra que não palavras simples. Procure este site; você encontrará muitas explicações sobre isso.

Mas há uma maneira bastante segura de obter o segundo programa para fazer a mesma coisa que o primeiro faz: mudar

echo $i

para

echo ${!i}

OK, primeiro de tudo, ${i} é praticamente o mesmo que $i . O ! fornece um efeito semelhante ao do comando eval - ${!x} procura o valor de x (por exemplo, $x ou ${x} ) e usa que como o nome da variável a ser pesquisada. Então, se x=foo , então ${!x} é o mesmo que $foo . O código acima faz o mesmo com i , buscando o parâmetro cujo nome é o valor de i .

A propósito, você deve sempre citar todas as referências a variáveis do shell (por exemplo, "$i" , "$#" , "$args" , "${i}" e "${!i}" ) a menos que você tenha uma boa razão para não e você tem certeza de que sabe o que está fazendo.

    
por 03.01.2016 / 00:09
4

O primeiro bloco itera (implicitamente) pelos argumentos da linha de comando "$@"

for i in "$@"    # same as your "for i"
do
    echo "$i"
done

O segundo bloco itera explicitamente no número de argumentos, imprimindo o índice da seguinte forma:

args=$#                          # number of command line args
for (( i=1; i<=$args; i+=1 ))    # loop from 1 to N (where N is number of args)
do
    echo $i
done

Dado que, de acordo com o seu exemplo, $# é 5, a variável $i recebe os valores 1 , 2 , 3 , 4 , 5 .

Como apontado em outra resposta (agora excluída), você pode referenciar os argumentos da linha de comando por índice como este:

args=$#
for (( i=1; i<=$args; i++ ))
do
    echo "$i - ${!i}"
done
    
por 02.01.2016 / 23:33

Tags