Bash: элегантный способ запустить команду и выйти, если процесс завершился с ошибкой - PullRequest
0 голосов
/ 03 октября 2018

У меня есть такая логика в скрипте Bash:

Запустить что-нибудь;
Если это не удалось, напечатать что-нибудь и остановить;
Если нет, запустить что-то еще.
И все этовыполняется в сеансе ssh.

Это, вероятно, тривиально, если я использовал $? и if / else.Но из-за удобства сопровождения сценария я ищу какое-то элегантное двухстрочное решение.

Это то, что у меня есть до сих пор

ssh ... '
ls attributes/*'$CONF_FILE'.rb || ls -l attributes/ && exit 1;
'$EDITOR' attributes/*'$CONF_FILE'.rb '$PART_VER';'

Однако это не имеет значения, что бы ни случилось.Поэтому я попытался:

ssh ... '
ls attributes/*'$CONF_FILE'.rb || (ls -l attributes/ && exit 1);
'$EDITOR' attributes/*'$CONF_FILE'.rb '$PART_VER';'

Однако exit выходит только из подоболочки.И выход из скрипта из подоболочки совсем не элегантен .

Есть ли простое двухстрочное решение?Возможно, другие операторы имеют приоритет?

Ответы [ 3 ]

0 голосов
/ 03 октября 2018

Не используйте подоболочку;используйте группу команд.

ssh ... "
  ls attributes/*'$CONF_FILE'.rb || { ls -l attributes/ && exit 1; };
  '$EDITOR' attributes/*'$CONF_FILE'.rb '$PART_VER';"

(Обратите внимание на изменение в кавычках; это лучше гарантирует, что результат локальных расширений параметров правильно указан на удаленном конце, хотя все еще будут проблемы, если расширения параметровсами по себе содержат одинарные кавычки. Правильное решение будет запускать явную оболочку на удаленном конце, принимая ваши локальные параметры в качестве аргументов, вместо использования интерполяции для построения сценария. Следующее не проверено, но я думаю, что я все правильно процитировал.

ssh ... sh -c '
          ls attributes/*"$1.rb" || { ls -l attributes/ && exit 1; };
          "$EDITOR" attributes/*"\$1.rb" "$2";
        ' _ "$CONF_FILE" "$PART_VER"

)

0 голосов
/ 03 октября 2018

Написано для ясности, правильности и удобства обслуживания - не краткость:

# store your remote script as a string. Because of the quoted heredoc, no variables are
# evaluated at this time; $1, $2 and $3 are expanded only after the code is sent to the
# remote system.
script_text=$(cat <<'EOF'
  CONF_FILE=$1; PART_VER=$2; EDITOR=$3
  shopt -s nullglob                   # Return an empty list for any failed glob
  set -- attributes/*"$CONF_FILE".rb  # Replace our argument list with a glob result
  if (( $# )); then                   # Check length of that result...
    "$EDITOR" "$@" "$PART_VER"        # ...if it's nonzero, run the editor w/ that list
  else
    ls attributes                     # otherwise, run ls and fail
    exit 1
  fi
EOF
)

# generate a single string to pass to the remote shell which passes the script text
# ...and the arguments to place in $0, $1, etc while that script is running
printf -v ssh_cmd_str '%q ' \
  bash -c "$script_text" '_' "$CONF_FILE" "$PART_VER" "$EDITOR"

# ...thereafter, that command can be run as follows:
ssh -tt ... "$ssh_cmd_str"
0 голосов
/ 03 октября 2018

Сейчас я прибегнул к дублированию условия, например:

ssh ... '
ls attributes/*'$CONF_FILE'.rb >  /dev/null || ls -l --color=always attributes/
ls attributes/*'$CONF_FILE'.rb >  /dev/null || exit 1;
'$EDITOR' attributes/*'$CONF_FILE'.rb '$PART_VER';'

(я использовал &>- как сокращение для перенаправления stdout и stderr на /dev/null, но это, вероятно, не правильносм. комментарий.)

...