我正在尝试编写一个非常简单的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
我确信这个解决方案相当简单,但我已经躲过了几个小时,没有多少谷歌搜索能够提供任何帮助。谢谢你看看。
答案 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所说,对于附加到文件的情况,这会失败,因为即使对于check
,tee
的输出也会被重定向命令。重定向再次发生在错误的级别。可以通过添加另一个间接级别来解决这个问题:
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
。