如何在 POSIX shell 中执行带有未知数量参数的命令?

如何在 POSIX shell 中执行带有未知数量参数的命令?

我想在当前目录中搜索多个单词。为了实现这一点,我使用类似的东西。

grep -e "word1" -e "word2" -R .

这很好用。

更进一步,我创建了一个字典文件,其中包含换行符上的每个单词,并且我想grep使用该字典创建命令。

例如我有这个字典文件

one
two
three
more

我想创建这个命令

grep -e "one" -e "two" -e "three" -e "more" -R .

我知道可以用bash这样的数组来完成:

pattern=()
while IFS= read -r line; do
    pattern+=("-e" "$line")
done < "$dictionary"

grep "${pattern[@]}" -R .

但是如何使用仅 POSIX shell 来完成此操作呢?

我知道我可以创建一个作为grep命令的字符串并使用 执行它eval,但由于字典文件可以是任何东西,这对我来说听起来不安全。

  • 有没有解决方案eval
  • 有没有“安全”的解决方案 eval

答案1

grep您不想使用提供的-f-F开关吗grep?从grep手册页:

   -F, --fixed-strings
        Interpret PATTERN as a list of fixed strings, separated by 
        newlines, any of which is to be matched.  (-F is specified by 
        POSIX.)

   -f FILE, --file=FILE
        Obtain patterns from FILE, one per line.  The empty file contains 
        zero patterns, and therefore matches nothing.  (-f is specified by
        POSIX.)

例子

$ grep -F somefile.txt -R .

答案2

POSIX shell 有一个数组:位置参数($1$2、 …),集体访问为"$@",并使用set --内置参数设置。更准确地说,当前调用堆栈上的每个函数实例都有一个数组,但在任何点都只能访问当前函数(或脚本,如果在任何函数外部)的位置参数数组。因此,如果您想使用此数组但又不想破坏脚本的参数,请在函数中工作。

作为sml已经备注了,您使用 grep 的特定用例可以通过使用-Fgrep 选项使其读取每个文件行一个模式来更简单地解决。但是,对于没有类似grep -F.

set -- -a -b
while IFS= read -r line; do
  set -- -e "$line"
done < "$dictionary"
mycommand "$@" more stuff

这叫mycommand -a -b line1 line2 … more stuff.

eval如果您需要操作多个文件名列表(或具有任意内容的其他字符串),您可以通过明智的使用和非常仔细的引用来完成。严格引用是很棘手的。下面的函数有两个参数:一个变量名和一个字符串;它将字符串的带引号的形式附加到变量。带引号的形式是单引号文字,单引号经过适当转义,适合 shell 解析。

append_to_quoted_list () {
  set -- "$1" "$(printf %s. "$2" | sed "s/'/'\\\\''/")"
  eval "$1=\"\${$1} '${2%?}'\""
}

这是一个示例用法,用于同时构建两个列表。它$command1使用作为参数传递给选项的行进行调用-e,然后$command2将这些行作为--foo=…选项传递。

list1= list2=
append_to_quoted_list list1 "$command1"
append_to_quoted_list list1 "$command2"
while IFS= read -r line; do
  append_to_quoted_list list1 -e
  append_to_quoted_list list1 "$line"
  append_to_quoted_list list2 "--foo=$line"
done < "$dictionary"
eval "$list1; $list2"

相关内容