Bash脚本中的文件重定向失败,但Bash终端没有

时间:2017-07-13 16:10:12

标签: linux bash shell io-redirection

我遇到的问题是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”字样。

3 个答案:

答案 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

这将运行命令并显示变量评估的输出。希望这将揭示语法的任何问题。