Variáveis dinâmicas no shell

1

Eu tenho um script a seguir que pegará a entrada (caminho de origem) do usuário e anexará o volume dentro do contêiner do docker

echo -n "Enter the source path: "

read path

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

O problema é que eu quero fazer um loop, para que o usuário possa fornecer vários caminhos de origem e possa ser anexado ao contêiner docker.

Por exemplo

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

etc, esse número da variável $path depende das entradas do usuário.

    
por smc 31.08.2018 / 05:59

3 respostas

6

Em bash , você deve usar uma matriz para manter os caminhos como lidos pelo usuário. Em geral, é melhor manter strings separadas (nomes de caminho) separadas, em vez de concatená-las em uma única string que depois você precisa analisar corretamente para extrair as strings constituintes originais.

#!/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

Aqui, o usuário é solicitado a inserir um caminho várias vezes até que pressione Ctrl + D . Os caminhos inseridos são salvos no array mypaths , que é apresentado de tal forma que docker pode usá-lo diretamente.

Quando não houver mais caminhos para ler, o comando docker será chamado. O "${mypaths[@]}" será expandido para os elementos citados individualmente da matriz mypaths . Como as entradas da matriz são armazenadas da maneira como estão (com -v como um elemento separado antes de cada string pathname:/opt/pathname formatada especialmente), isso será interpretado corretamente pelo shell e por docker . Os únicos caracteres que não serão tolerados nos nomes de caminho pelo código acima são as novas linhas, pois estão separando as linhas lidas por read .

O script acima também aceitaria entrada redirecionada de um arquivo de texto contendo um único caminho por linha de entrada.

Observe que a cotação é importante. Sem as aspas duplas em torno das expansões de variáveis, você não seria capaz de usar caminhos contendo espaços em branco, e você também teria problemas com caminhos contendo caracteres especiais para o shell.

Relacionados:

Para não- 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

Aqui, usamos a lista de parâmetros posicionais em vez de uma matriz (já que matrizes diferentes de $@ não estão disponíveis em sh em geral), mas o fluxo de trabalho é idêntico, além de imprimir o prompt explicitamente com printf .

Implementando a sugestão no final do comentário de Stéphane Chazelas , para que o script tenha nomes de caminho em sua linha de comando, em vez de lê-los a partir de sua entrada padrão. Isso permite que o usuário passe nomes de caminhos arbitrários para o script, mesmo aqueles que read não conseguem ler facilmente ou que um usuário não consegue digitar facilmente em um teclado.

Para bash usando uma matriz:

#!/bin/bash

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

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

Para sh usando a lista de parâmetros posicionais:

#!/bin/sh

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

docker run "$@" fedora

Ambos seriam executados como

./script.sh path1 path2 path3 ...
    
por 31.08.2018 / 07:59
3

Tente isso, os nomes dos diretórios não devem conter espaços:

#!/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

Digite algo como foo bar e ele será executado

docker run -v foo:/opt/foo/ -v bar:/opt/bar/ fedora
    
por 31.08.2018 / 07:27
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
    
por 31.08.2018 / 06:22