将CAT命令作为参数传递给函数

时间:2013-08-18 21:52:38

标签: bash function cat

我正在尝试编写一个非常简单的bash脚本来修改许多文件,并且我将每个命令的结果输出到日志中,以检查命令是否已成功完成。一切似乎都在工作,除了我无法将带变量的CAT传递给我的脚本 - 我一直收到cat: >>: No such file or directory错误。

#! /bin/bash

file1="./file1"
file2="./file2"

check () {
  if ( $1 > /dev/null ) then
    echo "     $1 : completed" | tee -a log
    return 0;
  else
    echo "ERR> $1 : command failed" | tee -a log
    return 1;
  fi
}

check "cp $file1 $file1.bak"            # this works fine
check "sed -i s/text/newtext/g $file1" # this works, too
check "cat $file1 >> $file2"          # this does not work

我尝试过引用命令的任意数量的组合。我可以使用它的唯一方法是使用以下内容:

check $(cat $file1 >> $file2)

但是,这不会将命令本身传递给check仅返回值,因此函数$1中的check携带/dev/null而不是执行的命令,这是不是我想要的特殊行为。

为了完整起见,log文件如下所示:

     cp ./file1 ./file1.bak : completed
     sed -i s/text/newtext/g ./file1 : completed
ERR> cat ./file1 >> ./file2 : command failed

我确信这个解决方案相当简单,但我已经躲过了几个小时,没有多少谷歌搜索能够提供任何帮助。谢谢你看看。

2 个答案:

答案 0 :(得分:0)

问题是cat命令中的I / O重定向不是解释为I / O重定向,而是解释为cat命令的简单参数。它不是cat,而是导致悲伤的I / O重定向。尝试使用管道也会给你带来麻烦。

可用于解决此问题的选项包括:

check "cp $file1 $file2" # Use copy instead of cat and I/O redirection; clobbers file2

check "eval cat $file1 >> $file2" # Use eval to handle I/O redirection, piping, etc

如果$file1$file2包含shell特殊字符,则eval选项很危险。

cp命令替换无需I / O重定向即可工作的内容。您甚至可以使用(微观)shell脚本来处理作业 - 脚本执行shell脚本,shell脚本处理重定向:

#!/bin/sh
exec cat ${1:?} >> ${2:?}

如果缺少参数1或2(但不反对额外参数),则会生成默认错误消息。

答案 1 :(得分:0)

编辑:我在下面首次尝试的方法并不常用。还有另一个技巧可以拯救这个,即使不使用bash魔法,但它变得丑陋。


在这种情况下,>>重定向发生在错误的级别。最后要求cat阅读./file,然后是>>,然后是./file2。要进行重定向,您需要在其他地方执行此操作(请参阅下文),或调用eval

我建议使用eval,而是重新调整函数check的逻辑。您可以将check重定向到顶层,例如:

check() {
    if "$@"; then
        echo "     $@ : completed" | tee -a log
        return 0
    fi
    echo "ERR> $@ : failed, status $?" | tee -a log
    return 1
}

check cp "$file1" "$file.bak"                     # doesn't print anything
check sed -i s/text/newtext/g "$file1" >/dev/null # does print, so >/dev/null
check cat "$file1" >> "$file2"

check调用中的双引号以及file1和/或file2获取*;之类的元字符,或白色空间等。)

编辑:正如@cdm和@rici所说,对于附加到文件的情况,这会失败,因为即使对于checktee的输出也会被重定向命令。重定向再次发生在错误的级别。可以通过添加另一个间接级别来解决这个问题:

append_to_file() {
    local fname
    fname="$1"
    shift
    "$@" >> "$fname"
}

check cp "$file1" "$file.bak"
check append_to_file /dev/null sed -e s/text/newtext/g "$file1"
check append_to_file "$file2" cat "$file1"

但是,现在,已完成和失败的消息在前面记录append_to_file,这真的非常笨拙。我想我会回到eval