You're executing a script on the remote machine. That script happens to contain $2
and $logfilepattern
(the text between single quotes is passed literally as an argument to the ssh
command, so it's a code snippet to execute on the other side). These refer to variables of the shell running on the remove side.
Actually, you're running two shells on the remote side, but not usefully so. SSH always invokes a shell; you can pass it multiple arguments but they're just joined with spaces in between. The shell on the remote side executes
bash -c \ #script string starts here
cd $2
…
The first line invokes bash
with two arguments: -c
and a single space. This invokes a shell to do nothing. The rest of the remote command is executed in the shell invoked by SSH.
The simple way to do what you're trying to do is
ssh "$1" "cd $2 && ls -l $logfilepattern"
Notes:
- Parsing the output of
ls
is pointless: for file in `ls *`
is a complex way of writing for file in *
, except that parsing the output of ls
breaks if the file names contain special characters.
- Both
$2
and $logfilepattern
are parsed as part of the script that's executed on the remote side. If they contain something like $(touch foo)
, then that piece of code will be executed. In this particular use case, it isn't necessarily a problem, but it's something you need to be aware of.
- Using
&&
after cd
ensures that the ssh
command will return immediately with a failure status if the cd
command fails.
If you want to pass content unmodified to a remote shell over SSH, using the command line alone is problematic, because whatever you pass is expanded on the remote side. One trick that often works (but not always, it depends on the configuration of SSH both on the client and on the server) is to use variables whose name begins with LC_
; these are assumed to be information about the locale, and often transmitted.
LC_DIRECTORY=$2 LC_LOGFILEPATTERN=$logfilepattern ssh "$1" 'cd "$LC_DIRECTORY" && ls -l $LC_LOGFILEPATTERN'
Note the quoting:
- The command to execute on the remote machine is
cd "$LC_DIRECTORY" && ls -l $LC_LOGFILEPATTERN
. It's in single quotes to pass that literal text as an argument to the ssh
command.
$LC_DIRECTORY
is in double quotes in the script that's executed on the remote side so that the cd
command is invoked on the content of the variable.
LC_LOGFILEPATTERN
is not double-quoted because it's a whitespace-separated list of wildcard patterns, which is precisely how an unquoted variable expansion is treated.
If you're unable to transmit variables, you'll need to add a layer of quoting to protect variables whose value contains special characters.
q_directory=$(printf %sa "$2" | sed s/\'/\'\\\'\'/g)
q_directory="'${directory%a}'"
q_logfilepattern=$(printf %sa "$logfilepattern" | sed s/\'/\'\\\'\'/g)
q_logfilepattern="'${q_logfilepattern%a}'"
ssh "$1" "logfilepattern=$q_logfilepattern; cd $q_logfilepattern && ls \$logfilepattern"
ls -l $logfilepattern
– cas Oct 04 '15 at 05:22for file in
ls $logfilepatterndo zcat $file | wc -l
function getlogcounts { echo in getlogcounts echo "$1" echo "$2"ssh "$1" bash -c ' cd "$2" for file in $logfilepattern do zcat $file | wc -l done ' }
Now I'm getting: bash: -c: option requires an argument
Sorry for the formatting... noob at this...
– Max Oct 04 '15 at 05:48for file in $logpattern; do ... ; done
is sufficient, and works better. – cas Oct 04 '15 at 05:51