Bash Command Line Arguments Passed to Sed via Ssh

Bash command line arguments passed to sed via ssh

Substitute an eval-safe quoted version of your command into a heredoc:

#!/bin/bash
# ^^^^- not /bin/sh; printf %q is an extension

# Put your command into a single string, with each argument quoted to be eval-safe
printf -v cmd_q '%q ' "$@"

while IFS= read -r hostname; do
# run bash -s remotely, with that string passed on stdin
ssh -q -o 'StrictHostKeyChecking no' "$hostname" "bash -s" <<EOF
$cmd_q
EOF
done < <(listNodes | grep -o -e "node-[0-9*]")

Why this works reliably (and other approaches don't):

  • printf %q knows how to quote contents to be eval'd by that same shell (so spaces, wildcards, various local quoting methods, etc. will always be supported).
  • Arguments given to ssh are not passed to the remote command individually!
    Instead, they're concatenated into a string passed to sh -c.
  • However: The output of printf %q is not portable to all POSIX-derived shells! It's guaranteed to be compatible with the same shell locally in use -- ksh will always parse output from printf '%q' in ksh, bash will parse output from printf '%q' in bash, etc; thus, you can't safely pass this string on the remote argument vector, because it's /bin/sh -- not bash -- running there. (If you know your remote /bin/sh is provided by bash, then you can run ssh "$hostname" "$cmd_q" safely, but only under this condition).
  • bash -s reads the script to run from stdin, meaning that passing your command there -- not on the argument vector -- ensures that it'll be parsed into arguments by the same shell that escaped it to be shell-safe.

bash script using sed command on remote server with ssh and special characters

The command passed to ssh is delimited by double quotes. Since there are also double quotes within the string being passed to sed, they will need to be escaped to prevent the shell from trying to take them:

    ssh -t user@ip "sed -i -e '/<!--insert_new_code-->/i\          <div class=\"col-lg-4 col-md-6\">\n            <?php include \"''explorers/'\"${coin_symbol_lower}\"'.php''\";?>\n          </div>\n\n' /home/some-data/some_dir/dir/dir/index.php"

Escaping $ variable in sed over ssh command?

The rule is that within single quotes, parameters are not expanded. You have single quotes around the entire command.

Try this:

ssh user@hostname "sed -e 's|foo|$bar|' /home/data/base_out.sql > /home/data/out.sql"

Now $bar is expanded before the command string is passed as an argument to ssh, which is what you want.

I removed the curly braces around ${bar} because I believe they offer a false sense of security. In this case, they are not protecting you against any of the issues associated using shell variables in sed commands.

use commandline arguments in a sed command

I'm not sure that $1, $2… and so on can be accessed from command line.

Instead, you could try to run your line from a function. You definitely can pass argument to functions.

foo() { sed 's/^\(.\{'"$2"'\}\)./\1'"$3"'/' "$1"; }
foo out2.fa 2 A

Edit: As suggested in comments, I added double-quotes around the argument references to prevent spaces from breaking command parsing (That should not be necessary around $2 as we just pass an integer, but it's much better for $1 and $3.

How to pass an argument with spaces to sed command?

Enclose the parameters ($1 etc) in double-quotes to keep them from being word-split (and prevent some other possibly unpleasant extra parsing):

sed -i "s/<div id=\"$1\"><p>*.*</<div id=\"$1\"><p>$2</" /var/www/html/alarm.html

Using SED in a ssh command on a remote node

I suggest to replace

ssh $i 'sed -i \'s/172.16.48.70/172.20.54.10/g\' /etc/hosts;'

by

ssh "$i" 'sed -i "s/172.16.48.70/172.20.54.10/g" /etc/hosts'

If you absolutely want to use single quotes:

ssh "$i" 'sed -i '"'"'s/172.16.48.70/172.20.54.10/g'"'"' /etc/hosts'

Adding single quotes into a sed command and also in a ssh command

Could you try the following command (replace the username, hostname accordingly to your needs):

ssh toto@localhost "sed '/0 => \x27192.168.0.32\x27/a 1 => \x27$old\x27,' /tmp/test"

output:

<?php
$CONFIG = array (
'trusted_domains' =>
array (
0 => '192.168.0.32',
1 => '1.1.1.1',
),
'dbtype' => 'mysql',
'dbport' => '',
'dbtableprefix' => 'oc_',
'logtimezone' => 'UTC',
'installed' => true,
'redis' =>
array (
'host' => '192.168.0.13',
'port' => 9095,
),
'mail_smtpmode' => 'sendmail',
'mail_from_address' => 'noreply',
'knowledgebaseenabled' => false,
0 => 18,
'loglevel' => 1,
'maintenance' => false,
);

If this works, just add -i options if you are really sure about what you are doing. you can also do the -i.bak to force sed to take a back up of your files

What is the significance of -n parameter passed to sed command?

From info sed:

-n:
By default, 'sed' prints out the pattern space at the end of each
cycle through the script (*note How 'sed' works: Execution Cycle.).
These options disable this automatic printing, and 'sed' only
produces output when explicitly told to via the 'p' command.

1p: print first line

1!p: do not print first line.



Related Topics



Leave a reply



Submit