Como usar argumentos como $ 1 $ 2… em um loop for? [duplicado]

7

Eu tenho este script que projetou para baixar a pronúncia das palavras que você dá como argumento:

#!/bin/bash 
m=$#
for ((i=1;i<=m;i++));do

echo $i
#wget https://ssl.gstatic.com/dictionary/static/sounds/de/0/"$i".mp3
done

se eu o executar por esse comando

./a.sh personality brave selfish

deve imprimir na stdout

personality 
brave 
selfish

mas em vez disso, imprime

1
2
3

você me ajudaria a resolver esse problema?

p.s: Se eu escrever o script sem loop por $ 1, por exemplo, ele funcionará corretamente, mas eu quero baixar muitos arquivos ao mesmo tempo

    
por AmirrezaFiroozi 03.10.2016 / 15:58

3 respostas

25

Em qualquer shell parecido com o Bourne, é:

for arg
do printf 'Something with "%s"\n' "$arg"
done

Ou seja, for faz um loop nos parâmetros posicionais ( $1 , $2 ...) por padrão (se você não der uma in ... part).

Note que isso é mais portátil do que:

for arg; do
  printf 'Something with "%s"\n' "$arg"
done

Que não era POSIX até a edição de 2016 do padrão nem Bourne (embora funcione na maioria dos outros shells semelhantes a Bourne incluindo bash mesmo no modo POSIX)

Ou então:

for arg in "$@"; do
  printf 'Something with "%s"\n' "$arg"
done

Qual é o POSIX, mas não funciona corretamente no shell Bourne ou no ksh88 quando $IFS não contém o caractere de espaço, ou com algumas versões do shell Bourne quando não há argumento, ou com alguns shells (incluindo alguns versões de bash ) quando não há argumento e a opção -u está ativada.

Ou

for arg do
  printf 'Something with "%s"\n' "$arg"
done

que é POSIX e Bourne, mas não funciona em shells muito antigas baseadas em cinzas. Eu pessoalmente ignoro isso e uso essa sintaxe como eu acho que é o mais legível e não espere que qualquer código que eu escrevo acabe sendo interpretado por um shell tão arcano.

Mais informações em:

Agora, se você quiser que $i faça um loop sobre [1..$#] e acesse os elementos correspondentes, faça o seguinte:

em qualquer shell POSIX:

i=1
for arg do
  printf '%s\n' "Arg $i: $arg"
  i=$((i + 1))
done

ou:

i=1
while [ "$i" -le "$#" ]; do
  eval "arg=\${$i}"
  printf '%s\n' "Arg $i: $arg"
  i=$((i + 1))
done

Ou com bash

for ((i = 1; i <= $#; i++ )); do
  printf '%s\n' "Arg $i: ${!i}"
done

${!i} sendo uma expansão de variável indireta, que é expandida para o conteúdo do parâmetro cujo nome é armazenado na variável i , semelhante ao sinalizador de expansão do parâmetro zsh P :

for ((i = 1; i <= $#; i++ )); do
  printf '%s\n' "Arg $i: ${(P)i}"
done
    
por 03.10.2016 / 16:24
3

Eu usaria shift . Esse [ -n "$1" ] significa que enquanto arg-1 não estiver vazio, continue em loop.

#! /bin/bash 
while [ -n "$1" ]; do
  echo "$1"
  wget "https://ssl.gstatic.com/dictionary/static/sounds/de/0/$1.mp3"
  shift
done
    
por 04.10.2016 / 09:18
0

maneira mais fácil

#!/bin/bash
for i
do
 echo $i
done

e execute

./a.sh personality brave selfish

e aqui está a impressão na stdout

personality
brave
selfish
    
por 03.10.2016 / 17:45