Как кратко присвоить переменной разные значения в зависимости от другой переменной?

Я только что получил ответ от своей хостинговой компании (OVH ). Получается, CIFS и NFS заблокированы за пределами своей сети. Предлагают использовать SSHFS, мы решили проблему с FTP.

20
26.07.2019, 18:27
5 ответов

Используйте оператор case(переносимый, работает в любойsh-подобной оболочке):

case "$CODE" in
    [aA] ) PN="com.tencent.ig" ;;
    [bB] ) PN="com.vng.pubgmobile" ;;
    [cC] ) PN="com.pubg.krmobile" ;;
    [dD] ) PN="com.rekoo.pubgm" ;;
    * ) printf '\a\t%s\n' 'ERROR!' 'CODE KOSONG' 'MELAKUKAN EXIT OTOMATIS' >&2
        exit 1 ;;
esac

Я бы также рекомендовал изменить имена ваших переменных с заглавных букв (, например CODE), на более низкий -или смешанный -регистр (, например codeилиCode). Есть много имен, полностью -заглавных букв, которые имеют особое значение, и повторное -использование одного из них по ошибке может вызвать проблемы.

Другие примечания :Стандартное соглашение состоит в том, чтобы отправлять сообщения об ошибках в «стандартную ошибку», а не в «стандартный вывод»; редирект >&2делает это. Кроме того, в случае сбоя сценария (или программы )лучше выйти с ненулевым статусом (exit 1), чтобы любой контекст вызова мог сказать, что пошло не так. Также можно использовать разные статусы для обозначения различных проблем (см. хороший пример в разделе «КОДЫ ВЫХОДА» на странице руководства curl). (Спасибо Стефану Шазеласу и Монти Хардеру за предложения.)

Я рекомендую printfвместоecho -eecho -n), потому что он более переносим между операционными системами, версиями, настройками и т. д. Однажды у меня сломалась куча моих скриптов, потому что обновление ОС включало скомпилированную версию bash. с различными опциями, которые изменили поведение echo.

Двойные -кавычки вокруг $CODEздесь на самом деле не нужны. Строка в case— один из немногих контекстов, где их можно безопасно опустить. Тем не менее, я предпочитаю двойные -кавычки ссылок на переменные, если только нет особой причины не делать этого, потому что трудно отследить, где это безопасно, а где нет, поэтому безопаснее просто двойное -цитирование.

62
27.01.2020, 19:43

Если ваша оболочка допускает массивы, самый короткий ответ должен быть похож на этот пример в bash:

declare -A site
site=( [a]=com.tencent.ig [b]=com.vng.pubgmobile [c]=com.pubg.krmobile [d]=com.rekoo.pubgm )

pn=${site[${code,}]}

Это предполагает, что $codeможет быть только a, b, c или d.
Если нет, добавьте тест, например:

case ${site,} in
    a|b|c|d)        pn=${site[${code,}]};;
    *)              pn="default site"
                    printf '\a\t %s\n' 'ERROR!' 'CODE KOSONG' 'MELAKUKAN EXIT OTOMATIS'
                    exit 1
                    ;;
esac
11
27.01.2020, 19:43

Если вы используете bashвыпуск 4.0 или новее...

CODE=A

declare -A domain

domain=(
   [a]=com.tencent.ig
   [b]=com.vng.pubgmobile
   [c]=com.pubg.krmobile
   [d]=com.rekoo.pubgm
)

PN=${domain[${CODE,,}]:?ERROR! CODE KOSONG, MELAKUKAN EXIT OTOMATIS}

В коде я определяю ассоциативный массив, содержащий все доменные имена, каждое из которых связано с одной буквой нижнего -регистра.

Переменной $PNприсваивается доменное имя, соответствующее нижнему -прописному $CODEзначению(${CODE,,}возвращает значение $CODE, переведенное в строчные буквы только )из этого массива, но если $CODEне соответствует действительной записи в списке domain, он завершает работу сценария с ошибкой.

Подстановка параметра ${variable:?error message}будет расширяться до значения$variable(соответствующего домена в коде ), но приведет к выходу из сценария с сообщением об ошибке, если значение пусто и недоступно. Вы не получите точно такой же формат сообщения об ошибке, как в вашем коде, но по существу он будет вести себя так же, если $CODEнедействителен:

$ bash script.sh
script.sh: line 12: domain[${CODE,,}]: ERROR! CODE KOSONG, MELAKUKAN EXIT OTOMATIS

Если вам небезразлично количество символов, мы можем еще больше сократить:

CODE=A
declare -A domain=( [a]=tencent.ig [b]=vng.pubgmobile [c]=pubg.krmobile [d]=rekoo.pubgm )
PN=com.${domain[${CODE,,}]:?ERROR! CODE KOSONG, MELAKUKAN EXIT OTOMATIS}

Помимо удаления ненужных новых строк, я также удалил com.из каждого домена (, вместо этого он добавлен в назначение дляPN).

Обратите внимание, что весь приведенный выше код будет работать даже для многозначного -символьного значения в $CODE(, если для них существуют ключи в нижнем регистре -в массиве domain).


Если бы $CODEбыл числовым (нулевым -основанным )индексом,это немного упростило бы код:

CODE=0

domain=( com.tencent.ig com.vng.pubgmobile com.pubg.krmobile com.rekoo.pubgm )
PN=${domain[CODE]:?ERROR! CODE KOSONG, MELAKUKAN EXIT OTOMATIS}

Это дополнительно упростило бы чтение массива domainиз вспомогательного файла, содержащего по одной записи в строке:

CODE=0

readarray -t domain <domains.txt
PN=${domain[CODE]:?ERROR! CODE KOSONG, MELAKUKAN EXIT OTOMATIS}
19
27.01.2020, 19:43

Вы используете буквы для индексации значений, если бы вы использовали числа, это было бы так же просто, как:

code=1
set -- com.tencent.ig com.vng.pubgmobile com.pubg.krmobile com.rekoo.pubgm

eval pn\=\${"$code"}

Это переносимый шелл-код, который будет работать на большинстве шеллов.
Для bash вы можете использовать :pn=${!code}, а для bash/ksh/zsh использовать:pn=${@:code:1}.

буквы

Если вы должны использовать буквы (от a до z или от A до Z ), они должны быть преобразованы в индекс:

code=a                              # or A, B, C,... etc.
set -- com.tencent.ig com.vng.pubgmobile com.pubg.krmobile com.rekoo.pubgm
eval pn\=\"\${$(( ($(printf '%d' "'$code")|32)-96  ))}\"

В более длинном коде для уточнения назначения и значения каждой части:

code=A

set -- com.tencent.ig com.vng.pubgmobile com.pubg.krmobile com.rekoo.pubgm

asciival=$(( $(printf '%d' "'$code") ))      # byte value of the ASCII letter.
upperval=$(( asciival |  32 ))               # shift to uppercase.
indexval=$(( upperval -  96 ))               # convert to an index from a=1.
eval arg\=\"\$\{$indexval\}\"                # the argument at such index.

Если вам нужно преобразовать значения в нижний регистр, используйте:$(( asciival & ~32 ))(убедитесь, что бит 6 значения ascii не установлен ).

код ошибки

Вывод, который ваш сценарий выводит при ошибке, довольно длинный (и конкретный ).
Самый универсальный способ справиться с этим — определить функцию:

errorcode(){ exitcode=$1; shift; printf '\a\t %s\n' "$@"; exit "$exitcode"; }

А затем вызовите эту функцию с конкретным сообщением (s ), которое вам нужно.

errorcode 27  "ERROR!" "CODE KOSONG" "MELAKUKAN EXIT OTOMATIS"

Обратите внимание, что результирующее значение выхода даетсяexitcode(пример здесь 27 ).

Полный скрипт (с проверкой ошибок )становится:

errorcode(){ exitcode=$1; shift; printf '\a\t %s\n' "$@"; exit "$exitcode"; }

code=${1:-A}

case "$code" in 
    [a-d]|[A-D]) : ;;
    *)           errorcode 27  "ERROR!" "CODE KOSONG" "MELAKUKAN EXIT OTOMATIS" ;;
esac

set -- com.tencent.ig com.vng.pubgmobile com.pubg.krmobile com.rekoo.pubgm
eval pn\=\"\${$(( ($(printf '%d' "'$code") & ~32) - 64  ))}\"

printf 'Code=%s Argument=%s\n' "$code" "$pn"
1
27.01.2020, 19:43

Я собираюсь ответить на этот вопрос в другом направлении. Вместо кодирования данных в сценарии поместите эти данные в отдельный файл данных, а затем используйте код для поиска в файле :

.
$ cat names.cfg 
a com.tencent.ig
b com.vng.pubgmobile
c com.pubg.krmobile
d com.rekoo.pubgm

$ cat lookup.sh
PN=$(awk -v code="${1:-}" 'tolower($1) == tolower(code) { print $2; }' names.cfg)
if [ -z "${PN}" ]; then
  printf '\a\t%s\n' 'ERROR!' 'CODE KOSONG' 'MELAKUKAN EXIT OTOMATIS' >&2
  exit 1
fi
echo "${PN}"

$ bash lookup.sh A
com.tencent.ig
$ bash lookup.sh a
com.tencent.ig
$ bash lookup.sh x
    ERROR!
    CODE KOSONG
    MELAKUKAN EXIT OTOMATIS

Разделение этих проблем имеет несколько преимуществ:

  • Добавляйте и удаляйте данные легко и просто, без необходимости обхода логики кода.
  • Другие программы могут повторно использовать данные, например, подсчитывать количество совпадений в определенном поддомене.
  • Если у вас есть огромный список данных, вы можете отсортировать его на диске и использоватьlookдля эффективного бинарного поиска (, а не по строкам -по -строкам grep] илиawk)
3
27.01.2020, 19:43

Теги

Похожие вопросы