当我运行命令时(在Ubuntu 14.04中,bash版本4.3.11),我们说当前目录中有一个名为text
的文本文件(并不重要) ):
nocommand > text # make sure noommand doesn't exists in your system
它会报告未找到的'命令'错误,它会删除文本文件!我只是想知道如果命令不存在我是否可以避免文件的破坏。
我尝试这个命令set -o noclobber
但是如果我运行会发生同样的问题:
nocommand >| text # make sure noommand doesn't exists in your system
似乎bash在查找要运行的特定命令之前重定向输出。谁能给我一些建议如何避免这种情况?
答案 0 :(得分:4)
实际上,shell首先查看重定向并创建文件。之后它会评估命令。
因此,究竟发生了什么:因为它是>
重定向,它首先用空文件替换文件,然后评估一个不存在的命令,这会在stderr上产生错误消息而什么都没有在stdout上。然后它将stdout存储在这个文件中(这没什么,所以文件保持为空)。
我同意Nitesh您只需要先检查命令是否存在,但根据this thread,您应该避免使用which
。我认为一个好的起点是在脚本的开头检查你可以运行所有必需的函数(参见线程,3个解决方案),否则就中止脚本。
答案 1 :(得分:3)
仅当管道发送至少一个字符时才会写入文件:
nocommand | (
IFS= read -d '' -n 1 || exit
exec >myfile
[[ -n $REPLY ]] && echo -n "$REPLY" || printf '\x00'
exec cat
)
或使用功能:
function protected_write {
IFS= read -d '' -n 1 || exit
exec >"$1"
[[ -n $REPLY ]] && echo -n "$REPLY" || printf '\x00'
exec cat
}
nocommand | protected_write myfile
请注意,如果启用了lastpipe
选项,则必须将其放在子shell中:
nocommand | ( protected_write myfile )
根据您的选择,您也可以默认在函数上召唤子shell:
function protected_write {
(
IFS= read -d '' -n 1 || exit
exec >"$1"
[[ -n $REPLY ]] && echo -n "$REPLY" || printf '\x00'
exec cat
)
}
()
召唤一个子贝壳。子shell是一个fork,在不同的进程空间上运行。在x | y
中,默认情况下会在子shell中召唤y
,除非lastpipe
选项(try shopt lastpipe
)已启用。IFS= read -d '' -n 1
等待一个字符(请参阅help read
)并在读取一个绕过exit
的字符时返回零代码。exec >"$1"
将stdout
重定向到文件。这使得打印到stdout
的所有内容都打印到文件中。\x00
以外的所有内容都存储在REPLY
中,这就是printf '\x00'
{null}(空)值时REPLY
的原因。exec cat
用cat
替换子shell的进程,该进程会将收到的所有内容发送到文件并完成剩余的作业。请参阅help exec
。答案 2 :(得分:3)
首先写入临时文件,只有在命令成功时才将其移动到所需文件上。
nocommand > tmp.txt && mv tmp.txt text
这不仅避免了nocommand
不存在时的错误,而且还避免了现有命令在完成写入输出之前退出时的错误,因此您不会用不完整的数据覆盖text
。 / p>
如果有更多工作,您可以在发生错误时清理临时文件。
{ nocommand > tmp.txt || { rm tmp.txt; false; } } && mv tmp.txt text
内部命令组确保外部命令组的退出状态为非零,这样即使rm
成功,也不会触发mv
命令。
一个更简单的命令,当nocommand
成功但mv
失败时,会带来轻微的删除临时文件的风险
nocommand > tmp.txt && mv tmp.txt text || rm tmp.txt
答案 3 :(得分:1)
如果你这样做:
set -o noclobber
然后
invalidcmd > myfile
如果当前路径中存在myfile
,那么您将获得:
-bash: myfile: cannot overwrite existing file
答案 4 :(得分:0)
使用"检查"命令
#!/usr/bin/env bash
command_name="npm2" # Add your command here
command=`which $command_name`
if [ -z "$command" ]; then #if command exists go ahead with your logic
echo "Command not found"
else # Else fallback
echo "$command"
fi
希望这有帮助