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 tosh -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 fromprintf '%q'
in ksh, bash will parse output fromprintf '%q'
in bash, etc; thus, you can't safely pass this string on the remote argument vector, because it's/bin/sh
-- notbash
-- running there. (If you know your remote/bin/sh
is provided by bash, then you can runssh "$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
Mmap Flag Map_Uninitialized Not Defined
Trouble with Installing Nloptr by Locally on Ubuntu
Socket Send Concurrency Guarantees
Reason of a Directory Size Being Zero
Setgid Bit Not Preserved by Git on New Directory in '.Git' Folder
How to Generic .Htaccess to Prevent Hotlink
Unzip in Current Directory While Preserving File Structure
How to Change Qmake Prefix Location
Can an Rpm Spec File "Include" Other Files
Dlopen with Two Shared Libraries, Exporting Symbols
Logging Memory Access Footprint
Linux: How to Send Tcp Packet from Specific Port
How to Install and Run Tacotron2 on Ubuntu Wsl
Why Isn't Git Bash Transforming The Path to *Nix Notation for My Python Installation