检查命令错误是否包含子字符串

时间:2017-07-30 20:56:02

标签: bash

我有很多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

3 个答案:

答案 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(dashbash快得多。)

您需要第一个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混合为一个输出,可以对其进行检查。问题是当您尝试使用交互式输出即topddrescue的复杂命令时,您需要保持标准输出不变,仅检查标准错误输出。 要忽略此问题,您可以尝试一下(仅在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