如何在 for 循环中使用 $1 $2 ... 之类的参数?

Ami*_*ozi 28 bash shell-script arguments

我有这个脚本,旨在下载您作为参数给出的单词的发音:

#!/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
Run Code Online (Sandbox Code Playgroud)

如果我通过这个命令运行它

./a.sh personality brave selfish
Run Code Online (Sandbox Code Playgroud)

它应该打印在标准输出上

personality 
brave 
selfish
Run Code Online (Sandbox Code Playgroud)

但它打印

1
2
3
Run Code Online (Sandbox Code Playgroud)

你能帮我解决这个问题吗?

ps:例如,如果我使用 $1 编写没有 for 循环的脚本,它将正常工作,但我想同时下载许多文件

Sté*_*las 51

在任何类似 Bourne 的 shell 中,它是:

for arg
do printf 'Something with "%s"\n' "$arg"
done
Run Code Online (Sandbox Code Playgroud)

也就是说,默认情况下会for在位置参数 ( $1, $2...)上循环(如果您不提供in ...零件)。

请注意,这比以下更便携:

for arg; do
  printf 'Something with "%s"\n' "$arg"
done
Run Code Online (Sandbox Code Playgroud)

直到 2016 年版本的标准和 Bourne 才开始使用 POSIX(尽管在大多数其他类似 Bourne 的 shell 中都可以使用,包括bash甚至在 POSIX 模式下)

或者比:

for arg in "$@"; do
  printf 'Something with "%s"\n' "$arg"
done
Run Code Online (Sandbox Code Playgroud)

这是 POSIX,但在$IFS不包含空格字符时在 Bourne shell 或 ksh88 中无法正常工作,或者在没有参数时使用某些版本的 Bourne shell,或者在没有参数时使用某些 shell(包括 的某些版本bash)参数并且该-u选项已启用。

或者比

for arg do
  printf 'Something with "%s"\n' "$arg"
done
Run Code Online (Sandbox Code Playgroud)

这是 POSIX 和 Bourne,但在非常旧的基于 ash 的 shell 中不起作用。我个人忽略了这一点并自己使用该语法,因为我发现它是最清晰的,并且不希望我编写的任何代码最终会被这种神秘的 shell 解释。

更多信息请访问:


现在,如果您确实想$i循环[1..$#]并访问相应的元素,您可以执行以下操作:

在任何 POSIX shell 中:

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

或者:

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

或与 bash

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

${!i}是一个间接变量扩展,即扩展到其名称存储在i变量中的参数的内容,类似于zshP参数扩展标志:

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

虽然在 中zsh,您还可以通过$argv数组访问位置参数(如在 中csh):

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