我遇到的问题是cmd1有效,但我的Bash脚本中的cmd2不是以.sh结尾。我已经使Bash脚本可执行。
此外,我可以从我的Bash终端执行cmd2。我试图制作一个可重复性最低的示例,但我的更大目标是使用命令行参数运行复杂的可执行文件,并将输出传递给可能存在或不存在的文件(而不是在终端中显示输出)。
更换>使用>>在脚本中也会出现相同的错误,但终端没有。
我的Bash脚本:
#!/bin/bash
cmd1="cat test.txt"
cmd2="cat test.txt > a"
echo $cmd1
$cmd1
echo $cmd2
$cmd2
test.txt在两行没有引号的情况下有“dog”和“cat”字样。
答案 0 :(得分:1)
简短回答:见BashFAQ #50: I'm trying to put a command in a variable, but the complex cases always fail!。
答案很长:shell在解析命令行的过程结束时扩展变量引用(如$cmd1
),在完成解析重定向之后(如{ {1}}应该是)和引用和转义......事实上,它对扩展值的唯一作用是分词(例如将> a
视为" cat"关注by" test.txt",">",最后" a"而不是单个字符串)和通配符扩展(例如{{1} }展开到cat test.txt > a
,它会用匹配文件列表替换$cmd
部分。 (如果变量是双引号,它会跳过单词拆分和通配符扩展。)
部分由于这个原因,将命令存储在变量中的最佳方法是:不要。这不是他们所要做的;变量用于数据,而不是命令。但是,您应该做的事情取决于为什么您将命令存储在变量中。
如果没有真正的理由将命令存储在变量中,那么只需直接使用该命令即可。对于条件重定向,只需使用标准cat *.txt
语句:
*.txt
如果您需要在某一点定义命令,并在以后使用它;或者想要反复使用相同的命令而不必每次都完全写出来,使用函数:
if
听起来您可能需要能够根据某些条件以不同方式定义命令,您实际上也可以使用函数来执行此操作:
if [ -f a ]; then
cat test.txt > a
else
cat test.txt
fi
或者,您可以将命令(不带重定向)包装在函数中,然后使用条件来控制它是否重定向:
cmd2() {
cat test.txt > a
}
cmd2
还可以将条件重定向包装到函数本身,然后将输出管道输出到它:
if [ -f a ]; then
cmd() {
cat test.txt > a
}
else
cmd() {
cat test.txt
}
fi
cmd
(这会创建一个额外的cmd() {
cat test.txt
}
if [ -f a ]; then
cmd > a
else
cmd
fi
进程,但它并没有真正做任何有用的事情,但是如果它让脚本更清晰,我认为值得。在这种特殊情况下,你可以使用maybe_redirect_to() {
if [ -f "$1" ]; then
cat > "$1"
else
cat
fi
}
cat test.txt | maybe_redirect_to a
最小化迷路cat
。)
作为最后的手段,您可以将命令字符串存储在变量中,并使用cat
来解析它。 maybe_redirect_to a < test.txt
基本上从头开始重新运行shell解析过程,这意味着它可以识别字符串中的重定向等内容。但是eval
作为一个错误的磁铁有着当之无愧的声誉,因为它很容易将你认为只是数据的字符串部分视为命令语法,这可能会导致一些非常奇怪(&amp;危险的错误。
如果你必须使用eval
,至少要对变量引用进行双引号,这样它只会在解析过程中运行一次,而不是像未引用的那样排序一次半。这是我的意思的一个例子:
eval
BashFAQ #50讨论了其他一些可能的原因和解决方案。请注意,这里的数组方法不起作用,因为在解析重定向后数组也会扩展。
答案 1 :(得分:0)
如果你在$ cmd2前面弹出'eval',它应该按预期工作:
#!/bin/bash
cmd2="cat test.txt > a"
eval $cmd2
答案 2 :(得分:0)
如果您不确定脚本的操作,可以始终使用调试模式来查看是否可以确定错误。
bash -x scriptname
这将运行命令并显示变量评估的输出。希望这将揭示语法的任何问题。