I am trying to add an argument to the flag batch start. This is the error it gives me. Any idea on how to fix this?
$ sed -i "s/batch_start.*/batch_start\ 1111/" /tmp/runfile
sed: -e expression #1, char 27: unterminated `s' command
The root problem is that the command is being sent over ssh; that means it's running through two levels of shell parsing, one on the local computer, then another on the remote computer. That means it goes through quote/escape parsing, application, and removal twice, so you need two "layers" of quoting/escaping.
The command in the last comment doesn't parse (mismatched quotes), but I can reproduce the error message with this command:
ssh remoteHost "sudo sed -i "s/batch_start.*/batch_start\ 1111/" /tmp/runfile"
This sort-of has two levels of quotes, but quotes don't nest, so it doesn't work. The local shell parses this as a double-quoted string "sudo sed -i ", then an unquoted section s/batch_start.*/batch_start\ 1111/ (which contains an escaped space, so it'll remove the escape), then another double-quoted section: " /tmp/runfile". Since there are no spaces between them, they all get passed to ssh as a single argument. You can see the post-parsing string by replacing ssh remoteHost with echo:
$ echo "sudo sed -i "s/batch_start.*/batch_start\ 1111/" /tmp/runfile"
sudo sed -i s/batch_start.*/batch_start 1111/ /tmp/runfile
...so that's the command the remote shell will execute. Since there's a space between s/batch_start.*/batch_start and 1111/, they get passed to sed as separate arguments, and it treats the first as the command to execute (which is missing a close /) and the second as a filename.
Solution: there are many ways to correct the quoting. You can use the echo trick to see what'll get sent to the remote shell. I tend to prefer single-quotes around the entire command, and then just quote normally inside that (as long as the inner command doesn't itself contain single-quotes). In this case, that means:
ssh remoteHost 'sudo sed -i "s/batch_start.*/batch_start 1111/" /tmp/runfile'
which executes this on the remote computer:
sudo sed -i "s/batch_start.*/batch_start 1111/" /tmp/runfile
(note that I removed the escape on the space.)
Related
I am trying to add a user "demouser" to /etc/sudoers of a remote server and I want to pass the username from a variable.
This works, but I want to use a variable $USERNAME instead of demouser
ssh centos#$remote_host -t 'sudo sed -i "\$ademouser ALL=(ALL) NOPASSWD:ALL" /etc/sudoers'
I tried using this but it's not working.
export USERNAME=demouser
ssh centos#remote_host bash -c "'sudo sed -i "\$a$USERNAME ALL=(ALL) NOPASSWD:ALL" /etc/sudoers'"
Error: -bash: syntax error near unexpected token `('
Parameters will not expand in single quotes, one can close them, and expand in double quotes instead:
ssh user#host 'sed "s/'"$localVar"'/replacement/" file'
^^
|Enter double quotes to avoid word splitting and globbing
Exit single quotes to expand on client side.
You should however know that the command send to the server is:
sed "s/abc/replacement/" file
Which might cause problems as we are now using double quotes on the server, one can send single quotes as well, but it quickly becomes as mess:
ssh user#host 'sed '\''s/'"$localVar"'/replacement/'\'' file'
^ ^
| Escaped remote single quote
Close local single quote
This will become:
sed 's/abc/replacement' file
I have a command like this:
ssh user#hostname 'sed -e "s|foo|${bar}|" /home/data/base_out.sql > /home/data/out.sql'
The sed command is working in local shell. But it is not expanding the variable over ssh command. Thanks!
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.
I'm trying to use the send command with a sed which uses a variable.
Having trouble to escape correctly.
send "sed "1i//$VAR" /file > /tmp/out\r"
If I use the sed command separately (which adds the $VAR text as first line of file), it works:
sed "1i//$VAR" /file > /tmp/out
But I can't figure out how to escape within the send command.
Inside double quotes, single quotes lose their special meaning, so you probably need:
send "sed '1i//$VAR' /file > /tmp/out\r"
On the local machine, the $VAR is placed into the command. On the remote machine, the sed command is enclosed in single quotes, protecting it from further abuse.
This should work:
send "sed '1i//$VAR' /file > /tmp/out\r"
Only the type of the outermost quotes matters for determining whether variables are interpolated.
I have written a bash script which calls a sed command (amongst other things) on a file to complete a find/replace of 2 different strings.
The trouble is, after running the script, I check the files and nothing has been updated. However, if I run the commands that are being produced (I echo them as output anyway) then they work.
For example, inside the script I have:
echo "/usr/local/bin/sed -i -e 's/${String1}/${String1R}/g;s/\/${String2}\//\/${String2R}\//g' ${ROOT_DIR}/data/file.sql"
/usr/local/bin/sed -i -e 's/${String1}/${String1R}/g;s/\/${String2}\//\/${TString2R}\//g' ${ROOT_DIR}/data/file.sql
Running the script does not change file.sql; however, if I run the command that is printed to console e.g. /usr/local/bin/sed -i -e 's/file_name1/file_name2/g;s//path_substring1///path_substring2//g' /path/to/file/file.sql it works perfectly!
Use double quotes instead of single quotes. Single quotes would prevent variable expansion.
/usr/local/bin/sed -i -e "s/${String1}/${String1R}/g;s/\/${String2}\//\/${TString2R}\//g" ${ROOT_DIR}/data/file.sql
Moreover, it seems that your variables are path strings which might contain forward slashes, i.e. /. In that event use a different separator:
"s|${String1}|${String1R}|g"
Using a different separator would obviate the need of escaping / in the pattern and replacement.
This question already has answers here:
Escape a string for a sed replace pattern
(17 answers)
Closed 9 years ago.
I have a sed command in a bash script like this:
sed -i 's/db.url=.*/db.url='$URL'/' config.properties
and URL var is assigned as:
$URL=jdbc\:oracle\:thin\:#\/\/hostname\:12345\/XYZ
When I run this bash script on the host it exists on it work as intended, replacing the url with the one specified in URL. However, when I add a command in the bash script to do this on my other host like this:
ssh user#host02 <<EOF
sed -i 's/db.url=.*/db.url='$URL'/' config.properties
exit
EOF
I get this error:
sed: -e expression #1, char 47: unknown option to `s'
Anyone know what may be going on here?
You've properly quote the sed expression if it were running on the local host, but the string is then passed to the shell on the remote host, where the * is now unquoted and expanded as a glob. The simplest thing to do is to pipe the command to the remote shell via standard input, so you don't have to worry about quoting:
echo "sed -i 's/db.url=.*/db.url=$URL/' config.properties" | ssh user#host02 bash
With multiple commands, you may consider using a here document:
ssh user#host02 bash <<EOF
command1
sed -i 's/db.url=.*/db.url=$URL/' config.properities
command2
EOF
The solution was to use double single quotes (') around $URL like this: ''$URL''