Execute o comando dentro da variável

4

Estou tentando executar um comando armazenado em uma variável:

cmd="grep -i \"word1\" filename | grep -i \"word2\""
eval $cmd

Mas quando executo o script, recebo os erros:

grep: |: No such file or directory
grep: grep: No such file or directory

Como posso executar comandos como o do meu exemplo sem receber esses erros?

    
por Kaj 22.12.2014 / 17:29

3 respostas

3

Você precisa citar "$cmd" - e talvez evite as aspas duplas " . De qualquer forma, para executar isso você precisa eval - e isso é devido ao |pipe . Uma variável de shell não se expande além dos limites de um único comando simples - e você está tentando executar um comando composto.

Então:

cmd='grep -i "word1" filename | grep -i "word2"'

eval "$cmd"

Provavelmente, quando você estava expandindo $cmd sem aspas, correu para geração de nome de arquivo e / ou $IFS problemas. Apenas certifique-se de que é citado de forma confiável e você ficará bem. Também verifique se o que está em "word[12]" não contém aspas duplas ou barras invertidas ou qualquer outra coisa - senão você precisará reavaliar seu estilo de citação lá.

Olhando mais de perto para o seu erro e posso dizer exatamente o que foi:

grep: |: No such file or directory
grep: grep: No such file or directory

Então, se eu fizer isso:

echo | echo

A primeira echo imprime uma \n ewline para a segunda echo ' stdin . Se eu fizer:

set \| echo
echo "$@"

O primeiro echo imprime cada um dos seus argumentos, que são | pipe e echo , respectivamente.

A diferença é que o | pipe no primeiro caso é interpretado pelo analisador do shell como um token e é interpretado como tal. No segundo caso, ao mesmo tempo em que o shell está verificando o token de | do canal, ele também está verificando o token $ expand - e assim o | pipe ainda não está lá porque "$@" tem ainda não foi substituído pelo seu valor.

Então, se você fizer isso:

grep -i "word" filename \| grep -i "word2"

... é provável que você obtenha os mesmos resultados porque o | não delimita os comandos e, em vez disso, é um argumento para grep em sua posição infiles .

Veja aqui quantos campos você recebe quando divide $cmd com o valor padrão $IFS :

printf '<%s> ' $cmd
<grep> <-i> <"word1"> <filename> <|> <grep> <-i> <"word2">

E aqui está o que a geração de nome de arquivo pode fazer:

touch 'echo 1simple &&' 'echo 2simple'
eval echo*
    
por 22.12.2014 / 20:12
0

Para o exemplo que você postou, você não precisa do eval. Apenas execute a variável da seguinte forma:

cmd="grep -i \"word1\" filename | grep -i \"word2\""; # added missing " at the end    
$cmd

Assista suas citações. Talvez algo assim seja menos propenso a erros:

cmd='grep -i "word1" filename | grep -i "word2"';
    
por 22.12.2014 / 17:38
0

Quanto a mim, é errado usar variável para salvar e executar qualquer comando. Há uma melhor escolha - função :

my_cmd() {grep -i "word1" filename | grep -i "word2"}

Isso é tudo.

Ou você pode usar argumentos diferentes como:

my_cmd() {grep -i "$1" "$3" | grep -i "$2"}

Em seguida, chame por

my_cmd word1 word2 filename
    
por 22.12.2014 / 18:02

Tags