skip to Main Content

I want to execute a docker command on a remote server. The problem is I don’t know to escape multiple quotes.

ret=$(ssh root@server "docker exec nginx bash -c 'cat /etc/nginx/nginx.conf | grep 'ServerName' | cut -d '|' -f1'")

I get

bash:  -f1: command not found

3

Answers


  1. Wrap your parameter string with N calls to "$(printf "%q" ...)", for N recursive calls .

    ssh root@server "docker exec nginx bash -c 'cat /etc/nginx/nginx.conf | grep ServerName | cut -d | -f1'"
    

    How may recursive calls the above line has? I don’t wish to set up docker just for the test, so I may have one of the following wrong:

    1. ssh – certainly counts
    2. docker – ??
    3. ngix – ??
    4. bash – certainly counts

    If there are four, then you need four calls to "$(printf "%q "str")", don’t forget to add all those " marks

    ssh root@server docker exec nginx bash -c "$(printf "%q" "$(printf "%q" "$(printf "%q" "$(printf "%q" "cat /etc/nginx/nginx.conf | grep ServerName | cut -d | -f1")")")")"
    

    Explanation: ssh parses the string like bash -c does, stripping one level of quotes. docker and nginx may also each parse the string (or not). Finally, bash -c parses whatever the previous levels have parsed, and removes the final level of quotes. exec does not parse the strings, it simply passes them verbatim to the next level.

    Another solution is to put the line, that you want bash to execute, into a script. Then you can simply invoke the script without all this quoting insanity.

    #!/bin/bash
    < /etc/nginx/nginx.conf grep ServerName | cut -d | -f1
    
    Login or Signup to reply.
  2. Consider using here-document :

    ret="$(ssh root@server << 'EOF'
    docker exec nginx bash -c "grep 'ServerName' /etc/nginx/nginx.conf | cut -d '|' -f1"
    EOF
    )"
    echo "$ret"
    

    Or, simpler as suggested by @MichaelVeksler :

    ret="$(ssh root@server docker exec -i nginx bash << 'EOF'
    grep 'ServerName' /etc/nginx/nginx.conf | cut -d '|' -f1
    EOF
    )"
    echo "$ret"
    
    Login or Signup to reply.
  3. There’s little need to execute so much on the remote host. The file you want to search isn’t likely that big: just pipe the entire thing down via ssh to a local awk process:

    ret=$(ssh root@server "docker exec nginx cat /etc/nginx/nginx.conf" |
             awk -F'|' '/ServerName/ {print $1}')
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search