wishlist: option to cause /bin/sh to be used instead of user's shell

Bob Proulx bob at proulx.com
Mon Sep 18 03:05:07 EST 2006


Daniel Kahn Gillmor wrote:
> when i have this situation, i often use:
>   ssh example.com "/bin/sh -c 'some command'"
> ...
> In either case, the quoting can become a little bit hairy if the
> command is large, but for simplish commands, it works without much
> trouble.  I'm sure someone else can produce a more reasonable quoting
> style.

Thank you for that suggestion.  And another kind person also made that
suggestion offlist.  That *almost* works.  The problem is that if the
login shell quoting rules are different than a sh-like shell's quoting
rules (which are tedious enough) then you still have to know the rules
for that particular shell to wrap everything in the first layer of
non-standard shell quoting for that host to eventually make it into
the standard shell.

Primarily I am talking about /bin/tcsh versus /bin/bash and /bin/ksh
in my environment.  Off the top of my head thinking of csh string
quoting I think I can quote everything sufficiently to make it work in
both of those shells.  But I find this to still be quite hard to get
right in practice.  In fact, I am not sure that I ever have been
completely successful when used by my clever users.  They are more
clever than I am.

Even if the shell is a standard /bin/sh everywhere the quoting rules
are complex.  For example using single-quotes means that you cannot
ever have a single-quote in the argument list because sh-like shells
do not allow a single-quote to be escaped by any method inside a
single-quoted string.  Therefore I prefer to use double-quotes because
it is possible to escape embedded double-quotes within a double-quoted
string.  It is also possible to programmatically escape shell
characters with things like perl/ruby modules[1].

When I don't need stdin just piping the commands to be run to the
remote shell is easiest.

  cat <<'EOF' | ssh example.com /bin/sh
  export foo=bar
  echo $foo
  EOF
  bar

My best method right now when I need stdin available is to use a
temporary file.  For your amusement here is an example.

  SERVER=example.com
  trap 'rm -f $TMPFILE; test -n "$RTMPFILE" && ssh -oBatchMode=yes -q -n $SERVER rm -f $RTMPFILE' EXIT
  TMPFILE=$(mktemp /tmp/foo.XXXXXX) || exit 1
  RTMPFILE=$(ssh -oBatchMode=yes -q -n -T $SERVER mktemp /tmp/foo.XXXXXX) || exit 1
  cat >$TMPFILE <<'EOF'
  echo "O'Hare"
  EOF
  scp -oBatchMode=yes -q $TMPFILE $SERVER:$RTMPFILE < /dev/null || exit 1
  ssh -oBatchMode=yes -q $SERVER sh $RTMPFILE
  exit $?

That works pretty well.  The biggest real issue my users saw with this
is that it is slower because of the multiple ssh invocations to the
remote host.  When I started on this problem ssh 3.8 was current and
there was no ssh connection sharing available.  Now that 4.2 has nice
connection sharing features I might be able to make the performance
with a temporary file good enough.  That still requires a persistent
connection however.  And at this moment in time many stable
distributions have yet to release again and so they still have the
older ssh 3.x without connection sharing until their next release.

Just the same let me suggest, wouldn't it be nice to have an option to
always be able to use a standard shell on the remote system? :-)

Thanks
Bob

[1] See perl's String::ShellQuote for one possibility.  But I think
this is still very tedious.  An attempt at printing O'Hare's $s:

  perl -MString::ShellQuote -le "print shell_quote(\"O'Hare's \\\$s\");"
  'O'\''Hare'\''s $s'
  perl -MString::ShellQuote -le 'print shell_quote("O'"'"'Hare'"'"'s \$s");'
  'O'\''Hare'\''s $s'

Trying to use this process to quote something for remote execution can
make scripts quite hard to read.



More information about the openssh-unix-dev mailing list