3

I am trying to retrieve shell variables generated on the remote machine in an ssh session.

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}

I have tried to pass variables from the ssh session (which are $mac_add and $timing) in this case, echo it on the local machine. Putting / in front of each variable doesn't help.

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

Same goes to adding export in front of each variable I want to declare. It doesn't solve the problem as well.

3
  • Do you want to do something with the variables locally or do you just want the output? If you don't need the data in variables, then just do the output form within the SSH session with ip link ... and date (i.e., don't capture the data in variables at all).
    – Kusalananda
    Commented Jan 4, 2021 at 8:16
  • yes i want the variable pass to outside of the ssh session(meaning i can echo out mac_add and timing) any way to have that? Thanks Commented Jan 4, 2021 at 9:15
  • 1
    Your ssh session and any other local shell are completely different processes, which do not share any variables at all, so you cannot refer to them locally. What you might do is get them via output from ssh command: ssh <target> <command> . So, e.g, ssh <target> 'echo ${mac_add}' might work. Or write a script on the target (in your first coding, e.g.), call that as <command>, and then assign the output to variables.
    – ridgy
    Commented Jan 4, 2021 at 10:36

2 Answers 2

2

Assuming the two commands executed on the remote host produces one line of output each:

{ 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
)

This reads the two lines produced by the remote commands into the two local variables mac_addr and timing. The data is passed to the two read calls by means of a redirected process substitution.

If you assume that the date command on the remote host will output the same thing as locally, then this can be simplified:

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
)

Or just

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

... running the awk command locally.


Just a short note about the rest of your code: Remember to double quote any variable expansion, and remember that read in bash can give the user a prompt if you use -p:

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

Also, Why is printf better than echo?

2
  • may i ask if there is a case statement , i want to obtain the result depends the case i have selected , how should i make the variable looks like according to this format mac_addr=$(sshpass -pthe@Donut ssh -o StrictHostKeyChecking=no "pi@$Rasp_id" <<'SSH_END' ip link show wlan0 | awk '/link/ { print $2 }' SSH_END ) Commented Jan 5, 2021 at 10:58
  • @TensorFlowGuan In that piece of code, the code that is executed on the remote host, i.e. the script in the here-document, can be arbitrarily complex.
    – Kusalananda
    Commented Jan 5, 2021 at 12:07
1

Since you want to retrieve output generated in your ssh session, you could try to store the output of the ssh session in total in a shell variable and then parse that output to extract the relevant bits.

The following should work. It will prepend the relevant lines with "start tags" to distinguish them from other messages (e.g. motd) that may be produced:

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")

The relevant values are then extracted via sed calls (by searching for and replacing the respective <tag>= part at beginning of the relevant lines with "nothing") and stored in bash variables local to your script.

4
  • Note that the output of date is likely the same on both the remote and local host.
    – Kusalananda
    Commented Jan 4, 2021 at 11:49
  • @Kusalananda In most cases I would agree, but in the case of a Raspberry PI as remote host you never know ... ;) Happy new year, btw.!
    – AdminBee
    Commented Jan 4, 2021 at 12:20
  • thanks for the advice , what if i have case statement inside the ssh session, i am afraid it will make the raw_output line complicated Commented Jan 5, 2021 at 1:20
  • @TensorFlowGuan I'm not sure I understand your concern: The command line will of course get longer, but would still work (you can write entire bash programs as one-liner if you want to). If you are concerned about internal buffer limits for the line-length, you can still use the here-doc approach you showed in your example.
    – AdminBee
    Commented Jan 6, 2021 at 9:15

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .