У меня есть оператор if elif elif else fi, который я хочу преобразовать в оператор case в сценариях bash. Вот код:
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
case $# in 3) ..;; 2) ..;; 1) ..;; 0) ..;; esac
@thatotherguy, yourprogram '' '' ''
все равно $#
будет 3, хотя -n
будет ложным для всех из них.
Я голосую за закрытие этого вопроса, потому что рекомендации Stack Overflow требуют практических вопросов, на которые можно ответить. if
более практично, чем case
в рассматриваемом сценарии.
Кстати, обратите внимание, что имена, написанные заглавными буквами, используются для переменных, которые изменяют поведение оболочки и утилит, указанных в POSIX, — ваши собственные переменные должны иметь хотя бы один символ нижнего регистра в своих именах. См. pubs.opengroup.org/onlinepubs/9699919799/basedefs/…, имея в виду, что переменные оболочки и среды имеют одно пространство имен.
мой босс хочет выписку по делу
Ваш босс просит что-то более сложное в обслуживании, чем исходный код. Если вы посмотрите на пример утверждения case
в моем ответе, он очень зависит от порядка; кто-то, кто модифицирует его, должен помнить о множестве предостережений при внесении изменений.
Во всяком случае, укажите их здесь; Я был бы рад расширить свой ответ по мере необходимости, чтобы обосновать дело.
(Кроме того, поскольку оператор case
может соответствовать только одному значению — даже если это составное значение — это означает, что вы обязательно должны иметь сигил, разделяющий поля, поэтому любое значение, передаваемое в качестве аргумента, содержащего этот сигил, нарушит все логика).
@AntonioContreras Вы уверены, что ваш босс не просил флаги с заявлением по делу? Это простой, канонический метод, который используют почти все другие инструменты.
@thatotherguy это именно то, о чем он просил: case $# in 4) # 3 additional input args - Do Stuff ;; 3) # 2 additional input args - Do Stuff ;; 2) # 1 additional input arg - Do Stuff ;; 1) # 0 additional input args - Do Stuff ;; esac
В примере нет проверок типа [[ -z $1 ]] && [[ -z $2 ]] && [[ -n $3 ]]
(2 пустых аргумента и один заполненный). Это действительно похоже на логику, основанную на $#
.
Короче говоря, это очень плохая идея. Однако, если у вас есть сигила, которая не может существовать в ваших значениях (демонстрация с помощью :
ниже), это можно сделать:
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
Однако использование расширения параметра default-value позволяет получить почти ту же логику гораздо яснее:
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
С $#
вы видите количество аргументов. Следующий case
работает иначе, когда вы используете ""
в качестве аргумента или имеете более 3 аргументов. Я думаю, это показывает, как ваш босс думает о case ... esac
.
Решение Чарльза лучше, ваш босс может также сказать вам, чтобы вы избегали повторяющихся строк.
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
Если я правильно понимаю, вы намерены использовать два способа вызова вашей программы:
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
Зачем тебе заявление
case
? Это не похоже на особенно хорошо подходит для одного.