我有很多bash命令。其中一些因各种原因而失败。 我想检查一些错误是否包含子字符串。
以下是一个例子:
#!/bin/bash
if [[ $(cp nosuchfile /foobar) =~ "No such file" ]]; then
echo "File does not exist. Please check your files and try again."
else
echo "No match"
fi
当我运行它时,错误被打印到屏幕上,我得到“不匹配”:
$ ./myscript
cp: cannot stat 'nosuchfile': No such file or directory
No match
相反,我希望捕获错误并符合我的条件:
$ ./myscript
File does not exist. Please check your files and try again.
如何正确匹配错误消息?
P.S。我找到了一些解决方案,您对此有何看法?
out=`cp file1 file2 2>&1`
if [[ $out =~ "No such file" ]]; then
echo "File does not exist. Please check your files and try again."
elif [[ $out =~ "omitting directory" ]]; then
echo "You have specified a directory instead of a file"
fi
答案 0 :(得分:7)
我会这样做
# Make sure we always get error messages in the same language
# regardless of what the user has specified.
export LC_ALL=C
case $(cp file1 file2 2>&1) in
#or use backticks; double quoting the case argument is not necessary
#but you can do it if you wish
#(it won't get split or glob-expanded in either case)
*"No such file"*)
echo >&2 "File does not exist. Please check your files and try again."
;;
*"omitting directory"*)
echo >&2 "You have specified a directory instead of a file"
;;
esac
这也适用于任何POSIX shell,如果您决定使用它可能会派上用场
将您的bash脚本转换为POSIX shell(dash
比bash
快得多。)
您需要第一个2>&1
重定向,因为可执行文件通常会将主要用于进一步处理机器的信息输出到stderr
。
您应使用>&2
重定向与echo
s,因为您输入的内容符合该类别。
答案 1 :(得分:1)
PSkocik's answer是正确的。但是,如果您正在寻找检测错误的方法:
检查退出代码而不是错误消息:
if cp nosuchfile /foobar
then
echo "The copy was successful."
else
ret="$?"
echo "The copy failed with exit code $ret"
fi
在查找子字符串之前,请查看命令的退出代码文档。例如,man wget
列出:
EXIT STATUS
Wget may return one of several error codes if it encounters problems.
0 No problems occurred.
1 Generic error code.
2 Parse error---for instance, when parsing command-line options
3 File I/O error.
(...)
在这种情况下,您可以直接查看:
wget "$url"
case "$?" in
0) echo "No problem!";;
6) echo "Incorrect password, try again";;
*) echo "Some other error occurred :(" ;;
esac
并非所有命令在退出状态下都是严格的,因此您可能需要检查子字符串。
答案 2 :(得分:0)
两个示例:
out=`cp file1 file2 2>&1`
和
case $(cp file1 file2 2>&1) in
具有相同的问题,因为它们将stderr和stdout混合为一个输出,可以对其进行检查。问题是当您尝试使用交互式输出即top
或ddrescue
的复杂命令时,您需要保持标准输出不变,仅检查标准错误输出。
要忽略此问题,您可以尝试一下(仅在bash> v4.2中工作!):</ p>
shopt -s lastpipe
declare errmsg_variable="errmsg_variable UNSET"
command 3>&1 1>&2 2>&3 | read errmsg_variable
if [[ "$errmsg_variable" == *"substring to find"* ]]; then
#commands to execute only when error occurs and specific substring find in stderr
fi
此行
command 3>&1 1>&2 2>&3 | read errmsg_variable
将stderr重定向到errmsg_variable(使用文件描述符技巧和管道)不与stdout混合。通常情况下,管道会产生自己的子流程,并且在使用管道执行命令后,所有分配在主流程中都是不可见的,因此在其余代码中检查它们是无效的。为避免这种情况,您必须使用以下方法更改标准外壳行为:
shopt -s lastpipe
与当前进程一样,在命令中执行最后一个管道操作,因此:
| read errmsg_variable
将内容“泵送”到管道(在我们的情况下为错误消息)分配给位于 main 进程中的变量。现在,您可以在其余的代码中检查此变量以找到特定的子字符串:
if [[ "$errmsg_variable" == *"substring to find"* ]]; then
#commands to execute only when error occurs and specific substring find in stderr
fi