执行包含双引号参数的命令(从外部文件读取)
Executing a command (read from an external file) containing Double quoted parameters
假设我有一个这样的 file.txt 文件:
some words
from here
blah blah blah
that begins
this is this
to here
other content
和另一个名为 *config.conf" 的文件,如下所示:
name1:value1
name2:value2
expr:sed -re "s/this/that/g" -ne "/from here/,/to here/ p"
name3:value3
name4:value4
在我的 script.sh 中,我需要获取 [=44= 中 "expr:" 之后编写的整个 sed 命令] 并像这样在管道中执行它:
#!/bin/bash
pipecommand=$(cat info | grep -e "^expr:" | sed -re "s/^expr://g")
cat file.txt | $pipecommand > output.file
但是我得到这个错误:
sed: -e expression #1, char 1: unknown command: `"'
我在这里读到了很多类似的问题,解决方案是使用这样的数组:
pipecommand=($(cat info | grep -e "^expr:" | sed -re "s/^expr://g"))
cat file.txt | ${pipecommand[@]} > output.file
不幸的是,这仅适用于不太复杂的命令,并且仅当我将 "sed...blah blah blah" 命令直接分配给变量时,而不是从文件中读取它。
你们中有人知道解决这个问题的有效方法吗?
P.S.: 我可以更改 script.sh 和 config.conf 文件.
遗憾的是,您需要评估。
pipecommand=$(grep "^expr:" info | cut -d: -f2-)
eval "$pipecommand" <file.txt > output.file
尽量避免 eval。
将您的配置文件变成一个具有明确接口的插件。在这里,您的脚本需要一个名为 sed_wrapper
的函数,因此您在 "config file" 中提供了一个具有该名称的定义(此处重命名为 lib.sh
)。
# This is lib.sh
sed_wrapper () {
sed -re "s/this/that/g" -ne "/from here/,/to here/ p"
}
然后,在您的脚本中调用命名函数。
. lib.sh
sed_wrapper < file.txt > output.file
将此解释为关于如何将 Reading quoted/escaped arguments correctly from a string 中的建议应用于您的用例的问题:
#!/usr/bin/env bash
# the sed expression here is modified to work with BSD sed, not only GNU sed
pipecommand=$(sed -ne 's/^expr://p' <info)
array=( )
while IFS= read -r -d ''; do
array+=( "$REPLY" )
done < <(xargs printf '%s[=10=]' <<<"$pipecommand")
<file.txt "${array[@]}" > output.file
这比 eval
更安全,因为 expr:
中的单词只能被视为文字参数,不能被解析为重定向、替换、参数扩展或其他 shell语法。当然,sh -c '...'
的 expr 可用于在 ...
部分启用 shell 语法:如果您真的想要沙箱,则必须限制命令(数组的第一个元素) , 控制或约束调用的命令。
假设我有一个这样的 file.txt 文件:
some words
from here
blah blah blah
that begins
this is this
to here
other content
和另一个名为 *config.conf" 的文件,如下所示:
name1:value1
name2:value2
expr:sed -re "s/this/that/g" -ne "/from here/,/to here/ p"
name3:value3
name4:value4
在我的 script.sh 中,我需要获取 [=44= 中 "expr:" 之后编写的整个 sed 命令] 并像这样在管道中执行它:
#!/bin/bash
pipecommand=$(cat info | grep -e "^expr:" | sed -re "s/^expr://g")
cat file.txt | $pipecommand > output.file
但是我得到这个错误:
sed: -e expression #1, char 1: unknown command: `"'
我在这里读到了很多类似的问题,解决方案是使用这样的数组:
pipecommand=($(cat info | grep -e "^expr:" | sed -re "s/^expr://g"))
cat file.txt | ${pipecommand[@]} > output.file
不幸的是,这仅适用于不太复杂的命令,并且仅当我将 "sed...blah blah blah" 命令直接分配给变量时,而不是从文件中读取它。
你们中有人知道解决这个问题的有效方法吗?
P.S.: 我可以更改 script.sh 和 config.conf 文件.
遗憾的是,您需要评估。
pipecommand=$(grep "^expr:" info | cut -d: -f2-)
eval "$pipecommand" <file.txt > output.file
尽量避免 eval。
将您的配置文件变成一个具有明确接口的插件。在这里,您的脚本需要一个名为 sed_wrapper
的函数,因此您在 "config file" 中提供了一个具有该名称的定义(此处重命名为 lib.sh
)。
# This is lib.sh
sed_wrapper () {
sed -re "s/this/that/g" -ne "/from here/,/to here/ p"
}
然后,在您的脚本中调用命名函数。
. lib.sh
sed_wrapper < file.txt > output.file
将此解释为关于如何将 Reading quoted/escaped arguments correctly from a string 中的建议应用于您的用例的问题:
#!/usr/bin/env bash
# the sed expression here is modified to work with BSD sed, not only GNU sed
pipecommand=$(sed -ne 's/^expr://p' <info)
array=( )
while IFS= read -r -d ''; do
array+=( "$REPLY" )
done < <(xargs printf '%s[=10=]' <<<"$pipecommand")
<file.txt "${array[@]}" > output.file
这比 eval
更安全,因为 expr:
中的单词只能被视为文字参数,不能被解析为重定向、替换、参数扩展或其他 shell语法。当然,sh -c '...'
的 expr 可用于在 ...
部分启用 shell 语法:如果您真的想要沙箱,则必须限制命令(数组的第一个元素) , 控制或约束调用的命令。