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

echo -n "Enter the raspberry ip address you want to connect:"
read Rasp_id

sshpass -pthe@Donut ssh -oStrictHostKeyChecking=no pi@"$Rasp_id" << 'E7'
        #sudo rm -r SoundEye.zip
        mac_add=$(ip link show wlan0 | grep link | awk '{print $2}')
        timing=$(date)
E7

echo ${mac_add}
echo ${timing}

Я попытался передать переменные из сеанса ssh (это $mac_add и $timing), в данном случае echo на локальном компьютере. Помещение / перед каждой переменной не помогает.

echo /${mac_add}
echo /${timing}

То же самое касается добавления экспорта перед каждой переменной, которую я хочу объявить. Тоже не решает проблему.

3
AdminBee 4 Янв 2021 в 14:12
Вы хотите сделать что-то с переменными локально или вам просто нужен результат? Если вам не нужны данные в переменных, просто выполните форму вывода в сеансе SSH с помощью ip link ... и date (т. е. вообще не собирайте данные в переменных).
 – 
Kusalananda
4 Янв 2021 в 11:16
Да, я хочу, чтобы переменная передавалась за пределы сеанса ssh (это означает, что я могу вывести mac_add и timing) каким-либо образом? Спасибо
 – 
TensorFlowGuan
4 Янв 2021 в 12:15
1
Ваша сессия ssh и любая другая локальная оболочка — это совершенно разные процессы, которые вообще не имеют общих переменных, поэтому вы не можете ссылаться на них локально. Что вы можете сделать, так это получить их через вывод команды ssh: ssh <target> <command> . Так, например, ssh <target> 'echo ${mac_add}' может работать. Или напишите сценарий для цели (например, в вашем первом кодировании), вызовите его как , а затем назначьте вывод переменным.
 – 
ridgy
4 Янв 2021 в 13:36

2 ответа

Предположим, что две команды, выполняемые на удаленном хосте, выдают по одной строке:

{ read mac_addr; read timing; } < <(
sshpass -pthe@Donut ssh -o StrictHostKeyChecking=no "pi@$Rasp_id" <<'SSH_END'
    ip link show wlan0 | awk '/link/ { print $2 }'
    date
SSH_END
)

Это считывает две строки, созданные удаленными командами, в две локальные переменные mac_addr и timing. Данные передаются двум вызовам read посредством перенаправленной подстановки процесса.

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

timing=$(date)
mac_addr=$(sshpass -pthe@Donut ssh -o StrictHostKeyChecking=no "pi@$Rasp_id" <<'SSH_END'
    ip link show wlan0 | awk '/link/ { print $2 }'
SSH_END
)

Или просто

timing=$(date)
mac_addr=$(sshpass -pthe@Donut ssh -o StrictHostKeyChecking=no "pi@$Rasp_id" ip link show wlan0 | awk '/link/ { print $2 }' )

... выполнение команды awk локально.


Небольшое примечание об остальном коде: не забывайте заключать в двойные кавычки любое расширение переменной и помните, что read в bash может дать пользователю подсказку, если вы используете -p:

read -p 'Enter the raspberry IP address you want to connect: ' Rasp_id

Кроме того, почему printf лучше, чем echo?

1
Kusalananda 4 Янв 2021 в 16:18
Могу я спросить, есть ли оператор случая, я хочу получить результат, зависит от случая, который я выбрал, как мне сделать, чтобы переменная выглядела в соответствии с этим форматом mac_addr=$(sshpass -pthe@Donut ssh -o StrictHostKeyChecking=no "pi@$Rasp_id" <<'SSH_END' IP-ссылка show wlan0 | awk '/link/ { print $2 }' SSH_END )
 – 
TensorFlowGuan
5 Янв 2021 в 13:58
В этом фрагменте кода код, который выполняется на удаленном хосте, то есть сценарий в этом документе, может быть сколь угодно сложным.
 – 
Kusalananda
5 Янв 2021 в 15:07

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

Следующее должно работать. Он будет добавлять к соответствующим строкам «начальные теги», чтобы отличить их от других сообщений (например, motd), которые могут быть созданы:

raw_output=$(sshpass -pthe@Donut ssh -oStrictHostKeyChecking=no pi@"$Rasp_id" 'echo "MAC=$(ip link show eth0 | awk '\''/^ *link/{print $2}'\'')"; echo "DATE=$(date)"')

mac_add=$(sed -E '/^MAC=/s/^[^=]+=//;t;d' <<< "$raw_output")
timing=$(sed -E '/^DATE=/s/^[^=]+=//;t;d' <<< "$raw_output")

Затем соответствующие значения извлекаются с помощью вызовов sed (путем поиска и замены соответствующей части <tag>= в начале соответствующих строк на «ничего») и сохраняются в переменных bash, локальных для вашего скрипта.

0
AdminBee 4 Янв 2021 в 14:38
Обратите внимание, что вывод date, вероятно, одинаков как на удаленном, так и на локальном хосте.
 – 
Kusalananda
4 Янв 2021 в 14:49
В большинстве случаев я бы согласился, но в случае Raspberry PI в качестве удаленного хоста вы никогда не знаете... ;) Кстати, с Новым годом!
 – 
AdminBee
4 Янв 2021 в 15:20
Спасибо за совет, что, если у меня есть оператор case внутри сеанса ssh, я боюсь, что это усложнит строку raw_output
 – 
TensorFlowGuan
5 Янв 2021 в 04:20
Я не уверен, что понимаю вашу озабоченность: командная строка, конечно, станет длиннее, но все равно будет работать (вы можете писать целые bash программы как однострочные, если хотите). Если вас беспокоят ограничения внутреннего буфера для длины строки, вы все равно можете использовать подход here-doc, который вы показали в своем примере.
 – 
AdminBee
6 Янв 2021 в 12:15