开发者问题收集

如何将检查多个值的链式 if 语句转换为 bash 中的 case 语句?

2020-12-14
64

我有一个 if elif elif else fi 语句,我想将其转换为 bash 脚本中的 case 语句。代码如下:

if [[ -n $1 ]] && [[ -n $2 ]] && [[ -n $3 ]]; then
    # sudoed audit or fsr w/ IP: set user, user home directory, IP.
    CURR_USER="$1";
    CURR_HOME="$2";
    ADDR="$3";
  elif [[ -n $1 ]] && [[ -n $2 ]] && [[ -z $3 ]]; then
    # sudoed audit or fsr w/o IP: set user, user home directory.
    CURR_USER="$1";
    CURR_HOME="$2";
    ADDR='';
  elif [[ -n $1 ]] && [[ -z $2 ]] && [[ -z $3 ]]; then
    # root w/ IP: set audit user, audit home directory, IP.
    CURR_USER='audit';
    CURR_HOME='/home/audit';
    ADDR="$1";
  else
    # root w/o IP: set audit user, audit home directory.
    CURR_USER='audit';
    CURR_HOME='/home/audit';
    ADDR="";
  fi

我尝试了以下操作,但没有成功

case $# in
   [[ -n $1 ]] && [[ -n $2 ]] && [[ -n $3 ]] )
    # sudoed audit or fsr w/ IP: set user, user home directory, IP.
    CURR_USER="$1";
    CURR_HOME="$2";
    ADDR="$3";;
  [[ -n $1 ]] && [[ -n $2 ]] && [[ -z $3 ]] )
    # sudoed audit or fsr w/o IP: set user, user home directory.
    CURR_USER="$1";
    CURR_HOME="$2";
    ADDR='';;
  [[ -n $1 ]] && [[ -z $2 ]] && [[ -z $3 ]] ) 
    # root w/ IP: set audit user, audit home directory, IP.
    CURR_USER='audit';
    CURR_HOME='/home/audit';
    ADDR="$1";;
  *                                         )
    # root w/o IP: set audit user, audit home directory.
    CURR_USER='audit';
    CURR_HOME='/home/audit';
    ADDR="";;
  esac
fi

我需要 case 语句的原因是我的老板认为 case 语句比 if elif else 语句更容易理解

3个回答

使用 $# 可以看到参数的数量。当您使用 "" 作为参数或有超过 3 个参数时,下一个 case 的工作方式会有所不同。我认为这表明了您的老板如何看待 case ... esac
Charles 的解决方案更好,您的老板可能还会告诉您避免重复的行。

case $# in
   3)
    # sudoed audit or fsr w/ IP: set user, user home directory, IP.
    CURR_USER="$1"
    CURR_HOME="$2"
    ADDR="$3";;
   2)
    # sudoed audit or fsr w/o IP: set user, user home directory.
    CURR_USER="$1"
    CURR_HOME="$2"
    ADDR='';;
   1)
    # root w/ IP: set audit user, audit home directory, IP.
    CURR_USER='audit'
    CURR_HOME='/home/audit'
    ADDR="$1";;
  *)
    # root w/o IP: set audit user, audit home directory.
    CURR_USER='audit'
    CURR_HOME='/home/audit'
    ADDR="";;
  esac

或使用默认值

CURR_USER='audit'
CURR_HOME='/home/audit'
ADDR=""
case $# in
   3)
    # sudoed audit or fsr w/ IP: set user, user home directory, IP.
    CURR_USER="$1"
    CURR_HOME="$2"
    ADDR="$3";;
   2)
    # sudoed audit or fsr w/o IP: set user, user home directory.
    CURR_USER="$1"
    CURR_HOME="$2";;
   1)
    # root w/ IP: set audit user, audit home directory, IP.
    ADDR="$1";;
  *)
    # root w/o IP: set audit user, audit home directory.
    ;;
  esac
Walter A
2020-12-14

简而言之,这是一个非常糟糕的想法。但是,如果您的值中不能存在符号(使用下面的 : 进行演示),则可以这样做:

case $1:$2:$3 in
  '::')  CURR_USER=audit; CURR_HOME=/home/audit; ADDR=;;
  *::)   CURR_USER=audit; CURR_HOME=/home/audit; ADDR=$1;;
  *:*:)  CURR_USER=$1;    CURR_HOME=$2;          ADDR=;;
  *:*:*) CURR_USER=$1;    CURR_HOME=$2;          ADDR=$3;;
esac

但是,使用默认值参数扩展可以让您更清楚地获得 几乎 完全相同的逻辑:

CURR_USER=${1:-audit}
CURR_HOME=${2:-/home/audit}
ADDR=$3

...或者,对于 完全 相同的逻辑:

CURR_USER=${1:-audit}
CURR_HOME=${2:-/home/audit}
if [ -z "$2" ] && [ -z "$3" ]; then
  ADDR=$1
else
  ADDR=$3
fi
Charles Duffy
2020-12-14

如果我理解正确的话,您的意图是通过两种方式来调用您的程序:

Usage: my_program CURR_USER CURR_HOME [ADDR] (1st form)
  or:  my_program [ADDR] (2nd form)

您可以将其写为:

if (( $# >= 2 )) ; then
    # sudoed audit or fsr:
    CURR_USER="$1"
    CURR_HOME="$2"
    ADDR="$3" # may be empty
else
    # root:
    CURR_USER=audit
    CURR_HOME=/home/audit
    ADDR="$1" # may be empty
fi

或者:

if (( $# >= 2 )) ; then
    # sudoed audit or fsr:
    CURR_USER="$1"
    CURR_HOME="$2"
    shift 2
else
    # root:
    CURR_USER=audit
    CURR_HOME=/home/audit
fi
ADDR="$1" # may be empty
ruakh
2020-12-15