Como usar argumentos como $1 $2 ... em um loop for?

Como usar argumentos como $1 $2 ... em um loop for?

Eu tenho este script que foi projetado para baixar a pronúncia das palavras que você fornece 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 executá-lo com este comando

./a.sh personality brave selfish

deve imprimir no stdout

personality 
brave 
selfish

mas em vez disso ele imprime

1
2
3

você me ajudaria a resolver esse problema?

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

Responder1

Em qualquer shell do tipo Bourne, é:

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

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

Observe 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 do tipo Bourne, inclusive bashno modo POSIX)

Ou então:

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

Que é POSIX, mas não funciona corretamente no Bourne Shell ou ksh88 quando $IFSnão contém o caractere de espaço, ou com algumas versões do Bourne Shell quando não há argumento, ou com alguns shells (incluindo algumas versões de bash) quando não há argumento e a -uopção está habilitada.

Ou então

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

que é POSIX e Bourne, mas não funciona em shells muito antigos baseados em ash. Eu pessoalmente ignoro isso e uso essa sintaxe, pois acho que é a mais legível e não espero que nenhum código que escrevo acabe sendo interpretado por um shell tão misterioso.

Mais informações em:


Agora, se quiser $ifazer um loop [1..$#]e acessar os elementos correspondentes, você pode fazer:

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 combash

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

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

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

Embora em zsh, você também pode acessar parâmetros posicionais por meio do $argvarray (como em csh):

for ((i = 1; i <= $#; i++ )); do
  printf '%s\n' "Arg $i: $argv[i]"
done

Responder2

Eu usaria shift. Este [ -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

Responder3

Caminho mais fácil

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

e corra

./a.sh personality brave selfish

e aqui está a impressão no stdout

personality
brave
selfish

informação relacionada