Eu tenho um script bash que cria uma linha de comando em uma seqüência de caracteres com base em alguns parâmetros antes de executá-lo de uma só vez. As partes que são concatenadas para a cadeia de comandos devem ser separadas por pipes para facilitar um "fluxo" de dados através de cada componente.
Um exemplo muito simplificado:
#!/bin/bash
part1=gzip -c
part2=some_other_command
cmd="cat infile"
if [ ! "$part1" = "" ]
then
cmd+=" | $part1"
fi
if [ ! "$part2" = "" ]
then
cmd+=" | $part2"
fi
cmd+="> outfile"
#show command. It looks ok
echo $cmd
#run the command. fails with pipes
$cmd
Por alguma razão, os canos não parecem funcionar. Quando executo esse script, recebo diferentes mensagens de erro relacionadas geralmente à primeira parte do comando (antes do primeiro canal).
Portanto, minha pergunta é se é possível ou não criar um comando dessa maneira, e qual é a melhor maneira de fazê-lo?
infile
exista no diretório atual?Respostas:
Tudo depende de quando as coisas são avaliadas. Quando você digita
$cmd
, o restante da linha é passado como argumento para a primeira palavra em$cmd
.Isso mostra que os argumentos passados para o
echo
comando são: "/etc/passwd
", "|
" (o caractere da barra vertical), "wc
" e "-l
".De
man bash
:fonte
Uma solução para isso, para referência futura, é usar "eval". Isso garante que, de qualquer maneira que a string seja interpretada pelo bash, seja esquecida e a coisa toda seja lida como se tivesse sido digitada diretamente em um shell (que é exatamente o que queremos).
Portanto, no exemplo acima, substituindo
com
Resolvi-o.
fonte
eval foo "a b"
seria o mesmo queeval foo "a" "b"
.O @waltinator já explicou por que isso não funciona como o esperado. Outra maneira de contornar isso é usar
bash -c
para executar seu comando:fonte
bash -c
, mas useeval
para executar o comando no processo atual.Possivelmente, a melhor maneira de fazer isso é evitar o uso
eval
e apenas o uso de uma matriz Bash e sua expansão embutida para criar todos os argumentos e executá-los no comando.fonte