bashdockerdocker-exec

Direct group of commands into `docker exec`


I have the following command that works fine and prints foo before returning:

docker exec -i <id> /bin/sh < echo "echo 'foo'"

I want to direct multiple commands into the container with one pipe, for example echo 'foo' and ls /. I have tried the following:

  1. This fails because it runs the commands on the host and pipes the output into the container:
    {
        echo "foo"
        ls /
    } | docker exec -i <id> /bin/sh
    
  2. This fails because it has bad syntax. It also runs on the host:

    {
        echo "foo"
        ls /
    } | docker exec -i <id> /bin/sh
    
  3. This one fails, but I would like to not use an array of strings anyway:

    for COMMAND in 'echo "foo"' 'ls /'
    do
        docker exec -i <id> /bin/sh < echo $COMMAND
    done
    

I've also tried several other methods like piping commands into tee or echo but haven't had any luck. If you would like to know why I want to do this seemingly ridiculous thing, it's because:


Solution

  • Use a here document.

    docker run -i --rm alpine /bin/sh <<EOF
    echo abc
    ls /
    EOF
    

    Note the difference between quoted and unquoted here document delimiter.

    docker exec -i <id> /bin/sh < echo "echo 'foo'"
    

    I think you meant to do:

    docker exec -i <id> /bin/sh < <(echo "echo 'foo'")
    

    which is just the same as:

    docker exec -i <id> /bin/sh <<<"echo 'foo'"
    

    @edit There is a cool little trick. The idea is to pipe the script itself except first lines to another subprocess, it's sometimes used by installer scripts:

    #!/bin/sh
    # output this script except first 4 lines to docker
    tail -n+5 "$0" | docker run -i --rm alpine /bin/sh -x
    exit  # we exit original script
    #!/bin/sh
    # inside docker now
    echo abc
    ls /
    

    Execution:

    $ bash -x ./script.sh
    + tail -n+5 ./script.sh
    + docker run -i --rm alpine /bin/sh -x
    + echo abc
    + ls /
    abc
    bin
    ...
    var
    + exit
    

    In a similar fashion you could use sed or another parsing tool to extract the only the relevant part between some marks for example.