Как я могу преобразовать связанный оператор if, проверяющий несколько значений, в оператор case в bash?

У меня есть оператор 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? Это не похоже на особенно хорошо подходит для одного.

chepner 14.12.2020 20:59
case $# in 3) ..;; 2) ..;; 1) ..;; 0) ..;; esac
that other guy 14.12.2020 21:00

@thatotherguy, yourprogram '' '' '' все равно $# будет 3, хотя -n будет ложным для всех из них.

Charles Duffy 14.12.2020 21:01

Я голосую за закрытие этого вопроса, потому что рекомендации Stack Overflow требуют практических вопросов, на которые можно ответить. if более практично, чем case в рассматриваемом сценарии.

Charles Duffy 14.12.2020 21:01

Кстати, обратите внимание, что имена, написанные заглавными буквами, используются для переменных, которые изменяют поведение оболочки и утилит, указанных в POSIX, — ваши собственные переменные должны иметь хотя бы один символ нижнего регистра в своих именах. См. pubs.opengroup.org/onlinepubs/9699919799/basedefs/…, имея в виду, что переменные оболочки и среды имеют одно пространство имен.

Charles Duffy 14.12.2020 21:07

мой босс хочет выписку по делу

Antonio Contreras 14.12.2020 21:08

Ваш босс просит что-то более сложное в обслуживании, чем исходный код. Если вы посмотрите на пример утверждения case в моем ответе, он очень зависит от порядка; кто-то, кто модифицирует его, должен помнить о множестве предостережений при внесении изменений.

Charles Duffy 14.12.2020 21:10

Во всяком случае, укажите их здесь; Я был бы рад расширить свой ответ по мере необходимости, чтобы обосновать дело.

Charles Duffy 14.12.2020 21:11

(Кроме того, поскольку оператор case может соответствовать только одному значению — даже если это составное значение — это означает, что вы обязательно должны иметь сигил, разделяющий поля, поэтому любое значение, передаваемое в качестве аргумента, содержащего этот сигил, нарушит все логика).

Charles Duffy 14.12.2020 21:15

@AntonioContreras Вы уверены, что ваш босс не просил флаги с заявлением по делу? Это простой, канонический метод, который используют почти все другие инструменты.

that other guy 14.12.2020 21:29

@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

Antonio Contreras 14.12.2020 22:09

В примере нет проверок типа [[ -z $1 ]] && [[ -z $2 ]] && [[ -n $3 ]] (2 пустых аргумента и один заполненный). Это действительно похоже на логику, основанную на $#.

Walter A 15.12.2020 00:35
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
12
56
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Короче говоря, это очень плохая идея. Однако, если у вас есть сигила, которая не может существовать в ваших значениях (демонстрация с помощью : ниже), это можно сделать:

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

Другие вопросы по теме