Как установить И расширить переменные в разделе heredoc

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

count=0

ssh $other_host <<ENDSSH
  if [[ "${count}" == "0" ]]; then
    output="string1"
  else
    output="string2"
  fi
  echo output
ENDSSH

Это не работает, потому что «выход» ничего не устанавливает.

Я попытался использовать решение из этого вопроса:

count=0

ssh $other_host << \ENDSSH
  if [[ "${count}" == "0" ]]; then
    output="string1"
  else
    output="string2"
  fi
  echo output
ENDSSH

Это тоже не сработало. Для $output установлено значение «string2», потому что $count не был расширен.

Как я могу использовать heredoc, который расширяет переменные из родительского скрипта, и устанавливает свои собственные переменные?


person user2824889    schedule 29.03.2017    source источник
comment
Он ведет себя так, как ожидалось. Код внутри heredoc выполняется на удаленном хосте и не видит инициализацию count=0.   -  person codeforester    schedule 29.03.2017
comment
Есть ли способ передать переменную (и пару других) в выполнение heredoc?   -  person user2824889    schedule 29.03.2017
comment
Здесь нет исполнения heredoc. Heredoc определяет строку. Строка передается в ssh, где она оценивается оболочкой.   -  person William Pursell    schedule 29.03.2017


Ответы (3)


Ты можешь использовать:

count=0

ssh -t -t "$other_host" << ENDSSH
  if [[ "${count}" == "0" ]]; then
    output="string1"
  else
    output="string2"
  fi
  echo "\$output"
  exit
ENDSSH

Мы используем \$output, чтобы он расширялся на удаленном хосте, а не локально.

person anubhava    schedule 29.03.2017
comment
Также обратите внимание, что значение $count передается из текущей оболочки в удаленную. - person anubhava; 29.03.2017

лучше не использовать stdin (например, с помощью here-docs) для передачи команд до ssh.

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

# Use a *literal* here-doc to read the script into a *variable*.
# Note how the script references parameter $1 instead of
# local variable $count.
read -d '' -r script <<'EOF'
  [[ $1 == '0' ]] && output='zero' || output='nonzero'
  echo "$output"
EOF

# The variable whose value to pass as a parameter.
# With value 0, the script will echo 'zero', otherwise 'nonzero'.
count=0

# Use `set -- '$<local-var>'...;` to pass the local variables as
# positional parameters, followed by the script code.
ssh localhost "set -- '$count'; $script"
person mklement0    schedule 29.03.2017

Вы можете экранировать переменные, как сказал @anubhava, или, если у вас слишком много переменных для экранирования, вы можете сделать это в два этапа:

# prepare the part which should not be expanded
# note the quoted 'EOF'
read -r -d '' commands <<'EOF'
if [[ "$count" == "0" ]]; then
    echo "$count - $HOME"
else
    echo "$count - $PATH"
fi
EOF

localcount=1
#use the unquoted ENDSSH
ssh [email protected] <<ENDSSH
count=$localcount # count=1
#here will be inserted the above prepared commands
$commands 
ENDSSH

напечатает что-то вроде:

1 - /usr/bin:/bin:/usr/sbin:/sbin
person jm666    schedule 29.03.2017