Bash: Каков наилучший синтаксис для условных выражений и (псевдо) булевых переменных - PullRequest
0 голосов
/ 21 марта 2020

Я прочитал много ответов на конкретные c варианты использования логического или условного синтаксиса в bash, но ни один из них не был признан наилучшей практикой, которая понадобилась бы многим (если вы этого не сделаете, я предлагаю вам прочитать эти вопросы, прежде чем продолжить с этим первый: поиск bash логических переменных и условных выражений и чтение первых пяти).

Сложность состоит в том, что bash не имеют одного, но много противоречивого, противоречивого и нелогичного синтаксиса для этого, хорошо отраженного в противоречивых ответах в SE.

Цель: знание того, что bash не имеет логических типов, но содержит условные операторы, операторы, коды состояния и функции, чтобы определить наилучший синтаксис для широкого использования логического исчисления и условного контроля выполнения в сценарии bash , Широкое распространение означает, что его можно использовать в командах условного управления, а также в переменных и операторах.

Передовой опыт должен соответствовать всем этим требованиям IMO в порядке наибольшей важности:

  1. сжато, если для операторов и троичный оператор?:
  2. краткое назначение и вызов переменных с логическим значением
  3. сжатые операторы булевого исчисления или, и, не, и круглые скобки с кодами возврата состояния команды и переменными

примеры конкурирующего синтаксиса:

  1. операторы: if [[ if [ if command if $variable
  2. назначения: t=true t=1 t=$(true) t='' t=0
  3. операторы: [ true -a false ] ( true && false ) (( true * false ))

Итак, какой синтаксис будет наилучшим для использования, например, для этого практического примера, но в других местах? :

 boolresutl1=if commandA or ( $numvarB > $numvarC ) then true
 boolresult2=commandD
 boolresult3=whatever

 if boolresult1 or boolresult2 and not boolresult3 then blabla

Наилучший ответ также продемонстрирует, что рабочие альтернативы предложенной передовой практике будут слишком многословными.

РЕДАКТИРОВАТЬ: здесь приведен фрагмент кода, который работает, но все еще может в ясности и краткости.

Цель логики - установить переменную keepFILE на основе набора временных условий на дату изменения файла и политики хранения файлов на годовой, квартальный, ежемесячный, еженедельный и ежедневный. И удалите файлы, не соответствующие этому условию. Моим ключевым выбором при разработке сценария было значение для истинного условия, между NULL (удовлетворяющим, если $ var, но не [[$ var]]), или "true" (удовлетворяющим [[$ var]], но не, если $ var) .

# date -d @12345 (seconds since epoch)  formats:  +%u (7= Sunday)  +%d (01= 1st dom) +%m (01=Jan) 
    unset isY isQ isM isW
# is beg of Week ?
[[ "$(date -d @$filedatesecs +%u)" =  7 ]] && isW=true
# is beg of Month ?
[[ "$(date -d @$filedatesecs +%d)" = 01 ]] && isM=true
# is beg of Quarter ?
[[ $isM && $(date -d @$filedatesecs +%m) =~ ^(01|04|07|10)$  ]] && isQ=true
# is beg of Year ?  
[[ $isM &&  "$(date -d @$filedatesecs +%m)" = 01 ]] && isY=true


unset keepD keepW keepM keepQ keepY keepFILE
    [[ $fileagedays -le $maxdaysD ]] && keepD=true
    [[ $fileagedays -le $maxdaysW ]] && [[  $isW ]] && keepW=true
    [[ $fileagedays -le $maxdaysM ]] && [[  $isM ]] && keepM=true
    [[ $fileagedays -le $maxdaysQ ]] && [[  $isQ ]] && keepQ=true
    [[ $fileagedays -le $maxdaysY ]] && [[  $isY ]] && keepY=true
    [[ $keepD || $keepW || $keepM || $keepQ || $keepY ]] && keepFILE=true

1 Ответ

1 голос
/ 21 марта 2020

Ваш псевдокод

# boolresutl1=if commandA or ( $boolvarB > $boolvarC ) then true
# boolresult2=commandD
# boolresult3=whatever

# if boolresult1 or boolresult2 and not boolresult3 then blabla

лучше всего написать с чем-то вроде

# Assuming `boolVarB` and `$boolvarC` are integer-valued.
if commandA || [ "$boolvarB" -gt "$boolvarC" ] || commandD && ! whatever; then
    blabla
fi

Обратите внимание, что || и && имеют одинаковый приоритет; whatever запускается только в случае сбоя commandA и [ и успешного завершения commandD. Если вам нужно сгруппировать вещи, используйте { ... ; }, например,

# Only run commandC if commandA fails and commandB succeeds,
# not when either commandA or commandB succeeds.
if commandA || { commandB && commandC; }; then

Если по какой-либо причине вам необходимо запомнить статусы выхода для последующего использования, немедленно сохраните результат $?:

commandA || [ "$boolvarB" -gt "$boolvarC" ]
result1=$?
commandD
result2=$?
whatever
result3=$?

...

if [ "$result1" -eq 0 ] || [ "$result2" -eq 0 ] || commandD && [ "$result3" -ne 0 ]; then
   blablabla
fi

Несколько комментариев:

  1. t=$(true) точно соответствует t=, за исключением того, что это занимает больше времени, потому что true ничего не записывает в стандартный вывод.
  2. Операторы -a и -o устарели и нестандартны. Никогда не используйте их; замена [ x -a y ] на [ x ] && [ y ] и [ x -o y ] на [ x ] || [ y ].
  3. (( true * false )) (для соответствующих целочисленных переменных) просто излишне запутана.
...