使用 grep 和命令行参数

使用 grep 和命令行参数

我有一个包含内容的文件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。我还引用了该模式以避免执行分词和文件名通配。

如果模式实际上是字符串而不是正则表达式,则考虑使用grepwith -F

位置参数列表可用作"$@",并且上面的循环隐式使用它。要循环"$@",请使用

for pattern in "$@"; do
   ...
done

请注意,引用是必不可少的,否则您将对脚本的参数执行分词和文件名匹配。

这个答案中没有任何 shell 代码需要bash,所以我在 -line/bin/sh中使用#!

答案2

如何使脚本将变量解释i为位置参数?

也许在 Bash 中获取由变量索引的位置参数的最简单方法是将数组切片表示法应用于$@."${@:n:k}"扩展到位置参数nn+k-1,就像扩展到从到 的"${array[@]:n:k}"数组元素一样。"${array[n]}""${array[n+k-1]}"nk使用 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 "$@"

相关内容