1

I have a following script that will take input (source path) from user and it will attach the volume inside docker container

echo -n "Enter the source path: "

read path

docker run -v $path:/opt/$path/ fedora

The problem is, i want to make a loop, so that the user can provide multiple source path and it can be attached to docker container.

E.g.

docker run -v $path1:/opt/$path1 -v $path2:/opt/$path2

etc , these number of $path variable depends on the user inputs.

GAD3R
  • 66,769
smc
  • 591
  • 3
  • 11
  • 25

3 Answers3

6

In bash, you should use an array to hold the paths as read from the user. In general, it's better to keep separate strings (pathnames) separate rather than to concatenate them into a single string that you later have to correctly parse to extract the original constituent strings.

#!/bin/bash

echo 'Enter paths, one by one followed by Enter. End input with Ctrl+D' >&2
mypaths=()
while IFS= read -r -p 'Path: ' thepath; do
   mypaths+=( -v "$thepath:/opt/$thepath" )
done

docker run "${mypaths[@]}" fedora

Here, the user is prompted to input a path several times until they press Ctrl+D. The paths entered are saved in the mypaths array, which is laid out in such a way that docker may use it directly.

Once there are no more paths to read, the docker command is called. The "${mypaths[@]}" will be expanded to the individually quoted elements of the mypaths array. Since the entries of the array are stored the way they are (with -v as a separate element before each specially formatted pathname:/opt/pathname string), this will be correctly interpreted by the shell and by docker. The only characters that will not be tolerated in pathnames by the above code are newlines, since these are separating the lines read by read.

The above script would also accept input redirected from a text file containing a single path per line of input.

Note that the quoting is important. Without the double quotes around the variable expansions, you would not be able to use paths containing whitespace, and you would potentially also have issues with paths containing characters special to the shell.

Related:


For non-bash (sh) shells:

#!/bin/sh

echo 'Enter paths, one by one followed by Enter. End input with Ctrl+D' >&2
set --
while printf 'Path: ' >&2 && IFS= read -r thepath; do
   set -- "$@" -v "$thepath:/opt/$thepath"
done

docker run "$@" fedora

Here we use the list of positional parameters instead of an array (since arrays other than $@ are not available in sh in general), but the workflow is otherwise identical apart from printing the prompt explicitly with printf.


Implementing the suggestion at the end of Stéphane Chazelas' comment, so that the script takes pathnames on its command line instead of reading them from its standard input. This allows the user to pass arbitrary pathnames to the script, even those that read can't easily read or a user can't easily type on a keyboard.

For bash using an array:

#!/bin/bash

for pathname do
    mypaths+=( -v "$pathname:/opt/$pathname" )
done

docker run "${mypaths[@]}" fedora

For sh using the list of positional parameters:

#!/bin/sh

for pathname do
    shift
    set -- "$@" -v "$pathname:/opt/$pathname"
done

docker run "$@" fedora

Both of these would be run like

./script.sh path1 path2 path3 ...
Kusalananda
  • 333,661
  • 1
    Note that prompting the users with path one per line like that means it can't accept arbitrary paths (like those that contain newline characters or byte values that cannot easily be entered on the keyboard. Even if you use bash's read -e where the user can use completion, that will still not allow users to enter paths with newlines (you'd need zsh's vared). Best would be to take the list of files from the arguments of the script, where the user can use the quoting or completion features of their shell to pass the arbitrary file names. – Stéphane Chazelas Sep 01 '18 at 08:42
  • @StéphaneChazelas Updated with your suggestion from that last sentence. – Kusalananda Sep 01 '18 at 09:34
3

Try this, the directory names must not contain spaces:

#!/bin/bash

echo -n "Enter the Directories, space separated : "
read dirs

docker run $( set -- $dirs; for path; do echo -v $path:/opt/$path/; done ) fedora

Enter something like foo bar, and it will run

docker run -v foo:/opt/foo/ -v bar:/opt/bar/ fedora
RalfFriedl
  • 8,981
2
#!/bin/bash

echo -n "Enter the Path : "
read path
echo -n "docker run "
echo "${path}" | tr " " "\n" | while read value
do
    echo -n "-v ${value}:/opt/${value} "
done
Kamaraj
  • 4,365
  • thanks @Kamaraj for the answer. However, I'm getting following output: "Enter the path: /var /tmp docker run -v /var:/opt/var docker run -v /tmp:/opt/tmp". But I'm expecting "Enter the path: /var /tmp docker run -v /var:/opt/var -v /tmp:/opt/tmp " – smc Aug 31 '18 at 04:49
  • try the edited answer – Kamaraj Aug 31 '18 at 05:38