-1

Need some help on these commands that we're not working during the ssh session but works fine when manually run on an ubuntu machine.

for w in $(echo "/var/asd/dsa/123" | tr "/" " ") ; do echo $w >&2; echo "123"; done

somehow the code above does not work, it expected to have an output like this:

var
123
asd
123
dsa
123
123
123

instead I get like this:

123
123
123
123
<blank space>
<blank space>
<blank space>
<blank space>

Here is the full code:

ssh -o "StrictHostKeyChecking no" -i $PEM_PATH $SERVER_USER@$SERVER_IP << EOF
    for w in $(echo "/var/asd/dsa/123" | tr "/" " ") ; do echo $w >&2; echo "123"; done
EOF

Any help are really appreciated, thanks!

2 Answers2

0

The problem is that the local shell is interpolating your $ expressions prior to sending them to the ssh session. You can prevent this by single quoting your heredoc tag: 'EOF'.

ssh -o "StrictHostKeyChecking no" -i $PEM_PATH $SERVER_USER@$SERVER_IP <<'EOF'
    for w in $(echo "/var/asd/dsa/123" | tr "/" " ") ; do echo $w >&2; echo "123"; done
EOF

With the above code, $(echo "/var/asd/dsa/123" | tr "/" " ") ; is sent to the server instead of being replaced locally.

Mark
  • 4,249
  • 1
  • 18
  • 27
  • Also, now that I look closer, `$w` is being replaced as well ( probably with nothing ). The 'EOF' will correct that as well. – Mark Mar 05 '20 at 17:07
  • in this case `$w` getting interpolated to empty string is the issue, `$(echo "/var/asd/dsa/123" | tr "/" " ")` has the same result executed locally or remotely. – Sorin Mar 05 '20 at 20:29
0

There are several issues with your approach:

Your here doc gets interpolated locally. The actual command you are running is: for w in var asd dsa 123 ; do echo >&2; echo "123"; done

You can see that by using set -x to enable tracing locally, and run ssh with cat instead of the login shell:

ssh pi cat << EOF
for w in $(echo "/var/asd/dsa/123" | tr "/" " ") ; do echo $w >&2; echo "123"; done
EOF

+ ssh pi cat
++ echo /var/asd/dsa/123
++ tr / ' '
for w in  var asd dsa 123 ; do echo  >&2; echo "123"; done

As you can see echo /var/asd/dsa/123 and tr / ' ' are executed locally, and $w is interpolated to the empty string.

You probably want to use single quotes around 'EOF':

ssh pi cat << 'EOF'
for w in $(echo "/var/asd/dsa/123" | tr "/" " ") ; do echo $w >&2; echo "123"; done
EOF

+ ssh pi cat
for w in $(echo "/var/asd/dsa/123" | tr "/" " ") ; do echo $w >&2; echo "123"; done

Now, the command gets there correctly.

Note: if you wish that $(echo "/var/asd/dsa/123" | tr "/" " ") is run locally, then you at least need to escape $w.

ssh pi << EOF
    for w in $(echo "/var/asd/dsa/123" | tr "/" " ") ; do echo \$w >&2; echo "123"; done
EOF

Buffering will mess up the order. That's why your empty lines (the ones printed by echo >&2) are at the end of your output. You can use tee to "force" line buffering:

ssh -T pi << 'EOF'
for w in $(echo "/var/asd/dsa/123" | tr "/" " ") ; do echo $w >&2; echo "123"; done
EOF

+ ssh -T pi
Linux mserv 3.10.25+ #622 PREEMPT Fri Jan 3 18:41:00 GMT 2014 armv6l
... 

123
123
123
123
var
asd
dsa
123

Versus:

ssh pi << 'EOF'
for w in $(echo "/var/asd/dsa/123" | tr "/" " ") ; do echo $w >&2; echo "123"; done 2>&1 | tee
EOF

+ ssh pi
Linux mserv 3.10.25+ #622 PREEMPT Fri Jan 3 18:41:00 GMT 2014 armv6l
...
var
123
asd
123
dsa
123
123
123

(in the first case STDIN is printed first, then STDERR, in the second, lines are alternated)

Piping commands to ssh and forcing a login shell If you run commands by piping them to stdin of ssh, it will run a login shell and print the MOTD (depending on the server configuration) and run a login shell (which has several side effects).

In my example, Linux mserv 3.10.25+ #622 PREEMPT Fri Jan 3 18:41:00 GMT 2014 armv6l is part of the MOTD. However, there is no need for piping, ssh will run last argument via the user shell, without the need for piping it to STDIN. This might be limited to MAX_ARG_STRLEN (which is ~128K), but if you have a script that size, you probably should scp-it to the host first.

$ ssh pi '
for w in $(echo "/var/asd/dsa/123" | tr "/" " ")
do
   echo $w >&2
   echo "123"
done 2>&1 | tee
'
var
123
asd
123
dsa
123
123
123

Note: This might be limited to MAX_ARG_STRLEN (which is ~128K), but if you have a script that size, you probably should scp-it to the host first.

Note: pi is a test server I use, replace it with your appropriate connection info.

Sorin
  • 5,201
  • 2
  • 18
  • 45