Search code examples
bashdockershellzshstdin

Sending list of filenames in current directory as a single string to a Docker container's STDIN


I have a Docker container and need to pass a single string (an array of strings would work too, but as far as I know this is not possible) containing the names of the file present in the current directory.

My first strategy to get the filenames inside the container was running the command docker build -t doc-validate . && docker run doc-validate (printf "%s " $(ls -p | grep -v /)) , to send the output of (printf "%s " $(ls -p | grep -v /)) directly into the container's STDIN, however, I get zsh: bad pattern: (printf %s Dockerfile returned as an error; seems to me that the container or the shell is trying to get 'Dockerfile' executed somewhere and I don't know why this happens, as running this same printf command directly in the terminal works as expected (printing only file names in the current directory).

My second approach was trying to send these filenames as an environment variable to the container. Running PROJECT_FILES=(printf "%s " $(ls -p | grep -v /)) in the terminal works as expected, $PROJECT_FILES outputs these filenames. However, if I try to pass it directly into the container like this: docker build -t doc-validate . && docker run --env PROJECT_FILES=(printf "%s " $(ls -p | grep -v /)) doc-validate I get the same zsh: bad pattern: PROJECT_FILES=(printf %s Dockerfile as an error.

Seems to me that it the commands are failing before even entering the container due to 'zsh:' being in the error output, however, I don't see why running them standalone in the terminal works and why passing them as parameters to the container is being such a headache.

How can I get the output of running (printf "%s " $(ls -p | grep -v /)) in my local machine as a value accessible inside the container?

Dockerfile:

FROM node:16
WORKDIR /moduleRoot
COPY package.json /moduleRoot
RUN npm install
COPY . /moduleRoot/
# Authorize execution of entrypoint bash script
RUN chmod +x /moduleRoot/docker-container-entrypoint.sh
# these values below will be set later, just register them explicitly here
ENV PROJECT_FILES=""
CMD [ "/moduleRoot/docker-container-entrypoint.sh" ]

Bash entrypoint (docker-container-entrypoint.sh file in CMD):

#!/bin/bash
echo "Args are: $@"
echo "PROJECT_FILES=$PROJECT_FILES"

Solution

  • First thing is that you are using the node:16 and according to the entrypoint of the project it will call node to execute anything you pass as an argument.

    On your Dockerfile you are calling a CMD and not changing the ENTRYPOINT, so when you execute the container it will try to execute the bash script using node and you must be getting an error like this:

    /moduleRoot/docker-container-entrypoint.sh:2
    echo "Args are: $@"
         ^^^^^^^^^^^^^^
    
    SyntaxError: Unexpected string
        at Object.compileFunction (node:vm:353:18)
        at wrapSafe (node:internal/modules/cjs/loader:1039:15)
        at Module._compile (node:internal/modules/cjs/loader:1073:27)
        at Object.Module._extensions..js (node:internal/modules/cjs/loader:1138:10)
        at Module.load (node:internal/modules/cjs/loader:989:32)
        at Function.Module._load (node:internal/modules/cjs/loader:829:14)
        at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:76:12)
        at node:internal/main/run_main_module:17:47
    

    If your bash script is there only to help you troubleshoot, then you can use the online heredoc to pass the arguments you need:

    » docker run -t --rm doc-validate <<< echo $(ls -a1)
    
    Args are: docker-container-entrypoint.sh Dockerfile package.json
    PROJECT_FILES=
    

    On the other hand, if you need the bash script then you'll have to change the CMD with ENTRYPOINT. Another thing worth noting is that Linux's ls doesn't have the -p flag.