문제

I am a noob in shell-scripting. I want to print a message and exit my script if a command fails. I've tried:

my_command && (echo 'my_command failed; exit)

but it does not work. It keeps executing the instructions following this line in the script. I'm using Ubuntu and bash.

도움이 되었습니까?

해결책

Try:

my_command || { echo 'my_command failed' ; exit 1; }

Four changes:

  • Change && to ||
  • Use { } in place of ( )
  • Introduce ; after exit and
  • spaces after { and before }

Since you want to print the message and exit only when the command fails ( exits with non-zero value) you need a || not an &&.

cmd1 && cmd2

will run cmd2 when cmd1 succeeds(exit value 0). Where as

cmd1 || cmd2

will run cmd2 when cmd1 fails(exit value non-zero).

Using ( ) makes the command inside them run in a sub-shell and calling a exit from there causes you to exit the sub-shell and not your original shell, hence execution continues in your original shell.

To overcome this use { }

The last two changes are required by bash.

다른 팁

The other answers have covered the direct question well, but you may also be interested in using set -e. With that, any command that fails (outside of specific contexts like if tests) will cause the script to abort. For certain scripts, it's very useful.

If you want that behavior for all commands in your script, just add

  set -e 
  set -o pipefail

at the beginning of the script. This pair of options tell the bash interpreter to exit whenever a command returns with a non-zero exit code.

This does not allow you to print an exit message, though.

Note also, each command's exit status is stored in the shell variable $?, which you can check immediately after running the command. A non-zero status indicates failure:

my_command
if [ $? -eq 0 ]
then
    echo "it worked"
else
    echo "it failed"
fi

I've hacked up the following idiom:

echo "Generating from IDL..."
idlj -fclient -td java/src echo.idl
if [ $? -ne 0 ]; then { echo "Failed, aborting." ; exit 1; } fi

echo "Compiling classes..."
javac *java
if [ $? -ne 0 ]; then { echo "Failed, aborting." ; exit 1; } fi

echo "Done."

Precede each command with an informative echo, and follow each command with that same
if [ $? -ne 0 ];... line. (Of course, you can edit that error message if you want to.)

Provided my_command is canonically designed, ie returns 0 when succeeds, then && is exactly the opposite of what you want. You want ||.

Also note that ( does not seem right to me in bash, but I cannot try from where I am. Tell me.

my_command || {
    echo 'my_command failed' ;
    exit 1; 
}

You can also use, if you want to preserve exit error status, and have a readable file with one command per line:

my_command1 || exit $?
my_command2 || exit $?

This, however will not print any additional error message. But in some cases, the error will be printed by the failed command anyway.

The trap shell builtin allows catching signals, and other useful conditions, including failed command execution (i.e., a non-zero return status). So if you don't want to explicitly test return status of every single command you can say trap "your shell code" ERR and the shell code will be executed any time a command returns a non-zero status. For example:

trap "echo script failed; exit 1" ERR

Note that as with other cases of catching failed commands, pipelines need special treatment; the above won't catch false | true.

The following functions only echoes errors if a command fails:

silently () {
    label="${1}"
    command="${2}"
    error=$(eval "${command}" 2>&1 >"/dev/null")

    if [ ${?} -ne 0 ]; then
        echo "${label}: ${error}" >&2
        exit 1
    fi
}
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top