1

I have this shell script where I want the CLI inputs to be fed into the SSH command. The first SSH command runs as expected whereas the second has runTests.sh's $1 and $2 set to ''. It seems like it is not substituting them in. Any insights on why that might be?

$1=7107
$2=development

ssh redacted@redacted -t 'zsh -l -c "source ~/.zshrc && ./runTests.sh 7107 development"'
ssh redacted@redacted -t 'zsh -l -c "source ~/.zshrc && ./runTests.sh $1 $2"'
  • Flag bash _or_ zsh, not both at once. They're two different shells, and not mutually compatible. – Charles Duffy Aug 16 '21 at 21:06
  • That said, after the clarifying edits, it looks like the "Assigning to a positional parameter" duplicate gets to the core of your question. `$1=7107` doesn't work. If you want to update a positional parameter's value, that's one of the things `set` is for. – Charles Duffy Aug 16 '21 at 21:18

2 Answers2

1

You are invoking three different shells: a local shell, a remote login shell, and a remote zsh shell. You need to carefully specify which one should be responsible for which parameter substitutions.

Your variables live in the local shell, but you are asking the remote login shell to expand them. This is why it fails.

Here's how you can have the local shell substitute them instead:

set -- 7107 development   # Assign $1 and $2
ssh redacted@redacted -t "zsh -l -c 'source ~/.zshrc && ./runTests.sh $1 $2'"

Since $1 and $2 are now in double quotes in your local shell, they expand, resulting in zsh -l -c 'source ~/.zshrc && ./runTests.sh 7107 development' on the remote side.

This in turn results in source ~/.zshrc && ./runTests.sh 7107 development in the nested zsh shell.

Ideally you'd also want to escape special characters in your data so that values with quotes or spaces work correctly:

ssh redacted@redacted -t "zsh -l -c 'source ~/.zshrc && ./runTests.sh \$1 \$2' _ $(printf %q "$1") $(printf %q "$2")"
that other guy
  • 116,971
  • 11
  • 170
  • 194
  • What's the zsh equivalent to `${var@Q}`? Wouldn't hurt to try to make this pass through the values safely regardless of their content. – Charles Duffy Aug 16 '21 at 21:14
0

$1, $2, $3, ... are reserved to be used as command parameters, for example if you script name is script.sh, when you run:

./script.sh foo bar baz

$1 will be foo, $2 will be bar and $3 will be baz.

Also you should not use spaces when assign. Try:

foo=7107
bar=development

ssh redacted@redacted -t 'zsh -l -c "source ~/.zshrc && ./runTests.sh 7107 development"'
ssh redacted@redacted -t 'zsh -l -c "source ~/.zshrc && ./runTests.sh $foo $bar"'

Please note security issues pointed out in comments.

Joaquin
  • 2,013
  • 3
  • 14
  • 26
  • 1
    There are security issues here. If `bar='$(rm -rf ~)'`, this code would be running a `rm` over on `redacted@redacted`, even though the values were safely quoted locally. – Charles Duffy Aug 16 '21 at 21:11
  • 3
    Terminology note: `$1` et al. are *not* variables. There are three kinds of parameter: positional (`$1`, `$2`, etc), special (`$0`, `$#`, `$@`, etc), and variables. Variables are parameters whose names are valid identifiers, and the only kind of parameter that can be set using direct assignment. – chepner Aug 16 '21 at 21:17