如果它是 glob 模式,如何扩展第二个参数?

How to expand 2nd argument if it's a glob pattern?

我正在尝试编写一个脚本来计算文件列表中某些模式的匹配次数并输出其结果。本质上我想这样调用命令:

count-per-file.sh str_needle *.c

并得到如下输出:

Main.c: 12
Foo.c: 1

脚本:

#!/bin/bash
# Count occurences of pattern in files.
#
# Usage:
#   count-per-file.sh SEARCH_PATTERN GLOB_EXPR
for file in ""; do
    count=$(grep -a "" "$file" | wc -l)
    if [ $count -gt 0 ]; then
        echo "$file: $count"
    fi
done

问题是如果我这样调用它,我不知道如何遍历文件列表,所以这不会输出任何内容:

count-per-file.sh str_needle *.c

我找到了 this answer,但它处理 glob 模式作为脚本的唯一参数,而在我的脚本中,第一个参数是搜索模式,其余的是从 glob 扩展的文件。

您可以像这样使用带有起始索引的子字符串参数扩展来跳过 $@

中的前 n-1 个值

"${@:n}"

例如

for FILE in "${@:2}" 
do
  echo $FILE
done

N.B. 您的脚本没有将 'glob pattern' 作为第二个参数。 调用您的脚本的 shell 将 glob 扩展为 space 分隔的文件列表 在您的脚本看到它之前 并将其作为参数列表传递给您的脚本。这就是为什么您可以使用 standard substring range expansion.

我想这就是你想要的

#!/bin/bash
# Count occurences of pattern in files.
#
# Usage:
#   count-per-file.sh SEARCH_PATTERN GLOB_EXPR
for file in ; do                               #UNQUOTE THIS TO EXPAND GLOB
    count=$(grep -a "" "$file" | wc -l)
    if [ $count -gt 0 ]; then
        echo "$file: $count"
    fi
done

然后在引号中传递 glob,这样它就不会在命令行中展开

count-per-file.sh str_needle '*.c'

您可以在传递 *.c 时添加引号,并在 for 循环中使用它们时删除引号,这将起作用..

[root@client1 ~]# cat  count-per-file.sh
#!/bin/bash
# Count occurences of pattern in files.
#
# Usage:
#   count-per-file.sh SEARCH_PATTERN GLOB_EXPR
for file in ; do
    count=$(grep -a "" $file | wc -l)
    if [ $count -gt 0 ]; then
        echo "$file: $count"
    fi
done
[root@client1 ~]# bash count-per-file.sh str_needle "*.c"
file.c: 1
Main.c: 12
[root@client1 ~]#

按照建议,我使用了 shift,这似乎是 'pop' 第一个参数。这是我的工作脚本:

#!/bin/bash
# Count occurences of pattern in files.
#
# Usage:
#   count-per-file.sh SEARCH_PATTERN GLOB_EXPR
search_pattern=""
shift

for file in "$@"; do
    count=$(grep -aiE "$search_pattern" "$file" | wc -l)
    if [ $count -gt 0 ]; then
        echo "$file: $count"
    fi
done