0

I am trying to manipulate the same text file across multiple hosts. The command I currently have it:

for host in $(cat /etc/hosts | grep text | cut -d' ' -f 1 | sort -u); do
    ssh $host \
    sudo sed -i "s/enabled = 1/enabled = 0/" /etc/yum.repos.d/testing.repo
done

The sed command itself works locally on the host with no problems however when I run it here, I get:

sed: -e expression #1, char 9: unterminated `s' command

What am I doing wrong?

2

Try this,

for host in $(grep test /etc/hosts | cut -d' ' -f 1 | sort -u); do
    ssh $host 'sudo sed -i "s/enabled = 1/enabled = 0/" /etc/yum.repos.d/testing.repo'
done

we should wrap around the remote commands with quotes.

| improve this answer | |
  • 1
    Pointing out the solution: The extra quotes around the remote commands. Also, would be better with a read loop (ssh -n would be needed). – Kusalananda Mar 27 '19 at 8:55
1

Try to change like this

for host in $(cat /etc/hosts | grep text | cut -d' ' -f 1 | sort -u); do
   ssh $host \
   "sudo sed -i \"s/enabled = 1/enabled = 0/\" /etc/yum.repos.d/testing.repo"
done
| improve this answer | |
  • Thanks! msp9011 – JinChin Mar 27 '19 at 9:01
1

The issue is that the command that is to be executed on the remote host relies on the quoting to be properly handled. The quotes needs to be evaluated as part of the command on the remote side, not on the local host. This means that the command needs an extra level of quotes.

Since your current attempt does not properly quote the command, it is split on whitespaces on the remote host. The sed command then becomes the equivalent of locally running

sed -i s/enabled = 1/enabled = 0/ /etc/yum.repos.d/testing.repo

which, as the error message says, contains an s command that is not properly terminated.

Also, looping over a command substitution is inelegant and hazardous. The value that the substitution expands to would be split into words on whitespaces, and the words would then undergo filename generation (globbing). It also requires the command substitution to be fully expanded before the loop could even start its first iteration.

Instead, use a read loop:

awk '/text/ && !seen[$1]++ { print $1 }' |
while IFS= read -r remote; do
    ssh -n "$remote" \
        'sudo sed -i "s/enabled = 1/enabled = 0/" /etc/yum.repos.d/testing.repo'
done

Note the ssh -n here. It stops ssh from reading its standard input stream, which would otherwise have it read the hosts that the awk command outputs. Also, any variable expansion should be double quoted (unless you know in what contexts this is not needed).

Another way to solve this issue would obviously be to, instead of editing the existing file on the various remote hosts, push a new copy of the file to each machine (possibly using scp or rsync). This would however require that the file should look the same on each host.

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.