我有一个包含内容的文件f1
:
james john joe
marie james
joe
don marie
我想grep
在 shell 脚本中使用s1.sh
以下内容输出每行中命令行参数的出现情况:
#!/bin/bash
for ((i = $# ; i > 0 ; i-- ))
do
grep -c $i f1
done
假设我执行如下:
s1.sh james joe
如何使脚本将变量解释i
为位置参数?
答案1
如果您想在调用 时一次使用脚本的参数,grep
则不需要执行算术for
循环:
#!/bin/sh
for pattern do
grep -c -e "$pattern" f1
done
该for
循环循环遍历位置参数,即脚本的参数。对于每次迭代,该值$pattern
将是下一个命令行参数。
我还使用-e
上面grep
的 来确保以破折号开头的模式不会被错误地解释为 的选项grep
。我还引用了该模式以避免执行分词和文件名通配。
如果模式实际上是字符串而不是正则表达式,则考虑使用grep
with -F
。
位置参数列表可用作"$@"
,并且上面的循环隐式使用它。要循环"$@"
,请使用
for pattern in "$@"; do
...
done
请注意,引用是必不可少的,否则您将对脚本的参数执行分词和文件名匹配。
这个答案中没有任何 shell 代码需要bash
,所以我在 -line/bin/sh
中使用#!
。
答案2
如何使脚本将变量解释
i
为位置参数?
也许在 Bash 中获取由变量索引的位置参数的最简单方法是将数组切片表示法应用于$@
."${@:n:k}"
扩展到位置参数n到n+k-1,就像扩展到从到 的"${array[@]:n:k}"
数组元素一样。"${array[n]}"
"${array[n+k-1]}"
n和k使用 shell 算术进行评估,因此您可以执行例如"${@:a+b-1:1}"
.仅"${@:i:1}"
给出位置 处的一个参数i
。
或者,间接扩展${!var}
也处理位置参数,因此例如 with i=2
,"${!i}"
将给出"$2"
。嗯,这也比上面的短。另一方面,namerefs不使用位置参数,declare -n ref=2
给出错误...
参见例如bash 是否支持使用指针?
另一种方法是将位置参数列表复制到命名数组,然后以通常的方式对其进行索引。args=("$@")
进行复制然后使用"${args[i]}"
。同样,这里的索引是算术展开式。
当然,如果您愿意访问位置参数上升顺序,像往常一样,实际上并不需要您显示的相反顺序,然后只需使用for x in "$@"; do ...
或for x do ...
,如 Kusalanda 的答案所示。
但是您也可以使用相同的循环构造首先反转位置参数列表。例如dd cc bb aa
,即使在没有命名者、间接引用或数组的普通 sh 中,这也会打印:
set -- aa bb cc dd
first=1
for x in "$@"; do
# on first iteration, clear the list
[ "$first" = 1 ] && set --
first=
set -- "$x" "$@"
done
echo "$@"