shell 脚本:什么时候测试最后一个命令?

shell scripting : when to test on the last command?

我有这个导入 mongo 数据库的小 bash 脚本,通过 运行 一个 java 程序对其进行一些更改,最后导出修改后的数据库:

#!/bin/bash

credentials="-u xx -p yy"

#import database
ssh user@$viaDbHost <<EOF
  scp user@$prodDumpHost:$prodDumpPath $viaDbWhitedumpTmpDir
  mongorestore --drop --host localhost --db whitedb $credentials --gzip --archive=$viaDbWhitedumpTmpDir/db.gz
  rm $viaDbWhitedumpTmpDir/db.gz
EOF

#run a java program
javacp=/appli/java/lib/*
java -cp "$javacp" xx.yy.zz.MyApplication

#export database
ssh user@$viaDbHost "mongodump --host localhost --db darkDb $credentials --gzip --archive=$darkdumpPath"

我想在发生错误时停止我的脚本并显示一条消息,所以我将 shell 更改为这个版本:

#!/bin/bash

credentials="-u xx -p yy"

#import database
ssh user@$viaDbHost <<EOF
  scp user@$prodDumpHost:$prodDumpPath $viaDbWhitedumpTmpDir

  if [ $? != 0 ]; then
    echo "@@@@@ ------- xxxxx"
    exit 1
  fi


  mongorestore --drop --host localhost --db whitedb $credentials --gzip --archive=$viaDbWhitedumpTmpDir/db.gz

  if [ $? != 0 ]; then
    echo "@@@@@ ------- yyyy"
    exit 1
  fi

  rm $viaDbWhitedumpTmpDir/db.gz

  if [ $? != 0 ]; then
    echo "@@@@@ ------- zzzz"
    exit 1
  fi
EOF

#run a java program
javacp=/appli/java/lib/*
java -cp "$javacp" xx.yy.zz.MyApplication

if [ $? != 0 ]; then
  echo "@@@@@ ------- blablabla"
  exit 1
fi

#export database
ssh nf2@$viaDbHost "mongodump --host localhost --db darkDb $credentials --gzip --archive=$darkdumpPath"

if [ $? != 0 ]; then
  echo "@@@@@ ------- blablabla 2"
  exit 1
fi

exit 0

我觉得因为这些测试,我的脚本变丑了,行数变多了!

有没有办法提高这篇文章的写作水平?
或者只检测要测试的线路的方法?

首先,确保将错误消息发送到 stderr。你可以试试:

!/bin/bash

credentials='-u xx -p yy'

die() { printf "%s${1:+\n}" "$*"; exit 1; } >&2
try() { "$@" || die "FAILED: $*"; }

#import database
ssh user@$viaDbHost <<EOF || exit
  scp user@$prodDumpHost:$prodDumpPath $viaDbWhitedumpTmpDir || { echo error >&2; exit 1; }

  mongorestore --drop --host localhost --db whitedb $credentials --gzip --archive=$viaDbWhitedumpTmpDir/db.gz || { echo error >&2; exit 1; }

  rm $viaDbWhitedumpTmpDir/db.gz || exit 1; # rm emits its own error message

EOF

#run a java program
javacp=/appli/java/lib/*
try java -cp "$javacp" xx.yy.zz.MyApplication

#export database
try ssh nf2@$viaDbHost "mongodump --host localhost --db darkDb $credentials --gzip --archive=$darkdumpPath"

exit 0

但老实说,对于此脚本,您可能甚至不需要费心发出任何错误消息。到处都做 cmd || exit 1,让每个命令发出自己的错误。

您可以或多或少地通用地执行此操作,而不必单独检查每个命令。启用 -e 选项(这会导致 bash 在命令失败时退出)并使用 EXIT 陷阱来提供一些细节:

#! /bin/bash

set -e

at_exit()
{
    local code=$?
    local cmd=$BASH_COMMAND

    if test $code -ne 0; then
      echo "Command <$cmd> failed with status $code!" >&2
    fi

    exit $code
}

trap at_exit EXIT

# ... your script here ...

您可以将它们放在一个公共文件中(例如 exit-trap.sh),然后 source 将其放入多个脚本中。

如果您希望整个脚本在命令失败时退出,您可以在末尾添加|| :

# don't exit if this fails
dont_care_if_it_fails || :