7

I have written an bash script foo.sh

#!/usr/bin/env bash
echo "starting the script";

I want to execute it in my remote server. I tried ssh user@remote-addr < test.sh and it worked.

After that I changed the test.sh file like this

#!/usr/bin/env bash
echo "starting the script";
echo $1;

now I want to pass a local parameter to execute with my script but when I type ssh user@remote-addr < test.sh testparam it returns an error.

How can I pass parameters with my scripts?

2
  • See answer here: unix.stackexchange.com/questions/87405/… Commented Nov 28, 2016 at 21:21
  • 1
    @Tim, ...I'm actually not sure any of the answers there are fully robust in the general case. Hmm. Might just copy my answer over there. Commented Nov 28, 2016 at 21:34

2 Answers 2

8

With bash or ksh as /bin/sh

If your remote /bin/sh is provided by bash or ksh, you can safely do the following with an untrusted argument list, such that even malicious names (like $(rm -rf $HOME).txt) can be passed as arguments safely:

runRemote() {
  local args script

  script=$1; shift

  # generate eval-safe quoted version of current argument list
  printf -v args '%q ' "$@"

  # pass that through on the command line to bash -s
  # note that $args is parsed remotely by /bin/sh, not by bash!
  ssh user@remote-addr "bash -s -- $args" < "$script"
}

...thereafter:

runRemote test.sh testparam

With Any POSIX-Compliant /bin/sh

Note that the following still needs to be run in bash, but will work correctly when the system being ssh'd into has a /bin/sh that is POSIX-baseline, so long as the remote machine has bash installed.

To be safe against sufficiently malicious argument data (attempting to take advantage of the non-POSIX compliant quoting used by printf %q in bash when nonprintable characters are present in the string being escaped) even with a /bin/sh that is baseline-POSIX (such as dash or ash), it gets a bit more interesting:

runRemote() {
  local script=$1; shift
  local args
  printf -v args '%q ' "$@"
  ssh user@remote-addr "bash -s" <<EOF

  # pass quoted arguments through for parsing by remote bash
  set -- $args

  # substitute literal script text into heredoc
  $(< "$script")

EOF
}

Similarly invoked as:

runRemote test.sh testparam
Sign up to request clarification or add additional context in comments.

Comments

3

Use the -s option, which forces bash (or any POSIX-compatible shell) to read its command from standard input, rather than from a file named by the first positional argument. All arguments are treated as parameters to the script instead.

ssh user@remote-addr 'bash -s arg' < test.sh

4 Comments

Make sure you put -- before arg so it is interpreted as an argument to test.sh instead of bash. Also, you probably want to use /usr/bin/env bash, as in the original script.
As-given, definitely correct for hardcoded arguments. Needs a bit more care to be safe for arbitrary arguments.
@Tim, the copy of /bin/sh evaluating the command is searching for bash in the PATH even without env, no?
@CharlesDuffy, I stand corrected. env is not needed in this case.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.