Inside here documents where the delimiter after <<
(here EOF
) is not quoted, the <backslash><newline>
sequence is removed, that's a line continuation.
Actually, the only cases where <backslash><newline>
is not removed is:
- inside single quotes
- inside here documents where the delimiter is quoted
- where the backslash itself is quoted (
<backslash><backslash><newline>
)
cat << EOF
foo\
bar
EOF
outputs
foobar
So, here you can do:
ssh user@server << EOF
command_one
command_two argument1 argument2 argument3 argument4 \
argument5 argument6 argument7
command_three
EOF
And ssh
will end up being fed:
command_one
command_two argument1 argument2 argument3 argument4 argument5 argument6 argument7
command_three
On its stdin.
Even if you used: ssh ... << 'EOF'
so as to avoid parameter expansion, command substitution and arithmetic expansion being performed inside the here-document, ssh
would be fed:
command_one
command_two argument1 argument2 argument3 argument4 \
argument5 argument6 argument7
command_three
But the remote shell would interpret that <backslash><newline>
as a line continuation, so it would have the same effect.
Note that when you do:
ssh user@server << EOF
sshd
on the remote host runs the user's login shell to interpret that code. Since it could be anything, not necessarily a Bourne-like shell, it may be better to run:
ssh user@server sh << EOF
Where sshd
runs user-s-login-shell -c sh
, so you know a Bourne-like shell is interpreting your code.
As an example that JVM_ARGS="-Xms512m -Xmx25000m" ./jmeter.sh...
is Bourne-shell or compatible syntax. It would work in csh
, tcsh
, rc
, es
, fish
shells, so wouldn't work with ssh user@server sh << EOF
if the login shell of user
on server
was one of those shells.
A significant difference though is that in that case, user-s-login-shell
is not started as a login shell so won't read /etc/profile
or ~/.profile
(or the equivalent for the user's login shell) to set the login session up.
Alternatively, you could convert that code to a syntax compatible to all those shells: env JVM_ARGS='-Xms512m -Xmx25000m' ./jmeter.sh...
(use single quotes instead of double quotes and use env
to pass an env var instead of the Bourne/rc specific envvar=value cmd
syntax).
The backslashes can be avoided by using xargs
:
ssh user@server sh << EOF
command_one
xargs command_two << END_OF_ARGS
argument1 argument2 argument3 argument4
argument5 argument6 argument7
END_OF_ARGS
command_three
EOF
Or by using a shell like rc
, ksh93
, zsh
, bash
, yash
and an array:
With rc
/zsh
syntax:
ssh user@server zsh << 'EOF'
command_one
args=(
argument1 argument2 argument3 argument4
argument5 argument6 argument7
)
command_two $args
command_three
EOF
(here quoting EOF
so that $args
is not expanded by the local shell).
Or with the ksh93
/bash
/yash
syntax (also works with zsh
):
ssh user@server bash << 'EOF'
command_one
args=(
argument1 argument2 argument3 argument4
argument5 argument6 argument7
)
command_two "${args[@]}"
command_three
EOF