我在评估严重口音时遇到了 bash 行为问题。我想使用可选的 -name 运行 find:
find -name "*.log"
工作正常,但是当我想从嵌套脚本中获取 -name 部分时
find `echo "-name \"*.log\""`
它根本不起作用。在 bash -x 下运行它显示,该命令被评估为
find -name '"*.log"'
显然是因为这个单引号。有一些解决方法可以摆脱它们吗?此致。
//请求的操作系统和bash版本:Debian、7.8 wheezy、Bash 4.2.37(1)-release
答案1
Bash 尚未在命令中添加单引号。添加您看到的单引号是为了使显示的命令成为有效的 bash 语法。如果你看到
find -name '"*.log"'
这意味着 bash 被告知执行此命令:find
带有两个参数-name
和"*.log"
(双引号是参数的一部分)。它可以完全像这样输入或以其他类似的方式输入
find -name \"*.log\"
find -name "\"*.log\""
find -name '"*.'log""\"
现在让我们看看您写的内容:
find `echo "-name \"*.log\""`
在子shell中运行的命令是
echo "-name \"*.log\""
它的输出是
-name "*.log"
这就是参数中双引号的来源。当命令替换的输出插入到命令行中时,它不会被解析为 shell 语法 - 例如
find `echo '; rm -rf ~'`
不会删除您的所有文件,而是;
作为第一个参数传递给find
,rm
作为第二个参数,-rf
作为第三个参数,并将您的主目录(假设它不包含任何特殊字符)作为第四个参数传递。
当变量替换或命令替换位于双引号之外时,变量的值或命令的输出会发生以下转换:
- 仅适用于命令替换:删除尾随换行符。
- 该字符串被分解为由空格分隔的片段。 (您可以通过设置变量来配置分隔符
IFS
。)请注意,此转换的结果是列表字符串。 - 列表中的每个元素都被解释为通配符模式。如果该模式与文件匹配,则该元素将被匹配文件列表替换(这称为通配)。如果该模式与任何文件都不匹配,则该元素将被保留。
步骤 2 将字符串-name "*.log"
分成两部分:-name
和"*.log"
。两个部分都不匹配任何文件,因此结果是两个单词-name
和"*.log"
。
您想做的是find
使用参数-name
和运行*.log
。您可以通过关闭通配符来做到这一点:
set -f
find `echo -name *.log`
set +f
这并不健壮:例如,它不允许您传递包含空格的文件名。一般来说,您不应尝试通过将命令的一些位存储在变量中或在命令中传递它们来构建命令。做你正在做的事情的最佳方法取决于你真正想做的事情。以下是一些一般建议:
答案2
使用函数 eval,这将解决您的问题
command="find `echo \"-name \"*.log\"\"`" response=$(eval "$command")