bash -c no subshell dá erro de análise de EOF

1

Por que o script a seguir funciona como esperado (imprime hello )

#!/bin/bash

foo=$(bash -c 'echo hello')
echo $foo

enquanto este script:

#!/bin/bash

cmd="bash -c 'echo hello'"
foo=$($cmd)
echo $foo

apresenta o seguinte erro:

hello': -c: line 0: unexpected EOF while looking for matching '''
hello': -c: line 1: syntax error: unexpected end of file
    
por user1658887 01.01.2016 / 15:28

2 respostas

4

Em

cmd="bash -c 'echo hello'"
$cmd

Você não está executando o comando bash -c 'echo hello' , está executando o comando $cmd simple.

Esse $cmd não indicado significa chamar o operador split + glob. Aqui, com o valor padrão de $IFS , o conteúdo de $cmd é dividido em bash , -c , 'echo e hello' . Então, você está executando bash com esses 4 argumentos, é como se você tivesse digitado:

bash -c "'echo" "hello'"

E esse código 'echo tem uma cotação de fechamento ausente (o argumento hello' entra no $0 desse script sequencial).

Se você quiser avaliar o conteúdo de $cmd como código shell, é

eval "$cmd"

Então:

cmd="bash -c 'echo hello'"
foo=$(eval "$cmd")
echo "$foo"

Embora você também possa usar seu operador split + glob de maneira diferente:

cmd='bash,-c,echo hello'
IFS=, # split on comma
set -f # disable glob
foo=$($cmd)
echo "$foo"
    
por 01.01.2016 / 16:03
1

Vamos dar uma olhada no que está sendo executado dentro de $($cmd) :

$ cmd="bash -c 'echo hello'"
$ foo=$(printf '<%s>' $cmd)
$ echo "$foo"
<bash> <-c> <'echo> <hello'>

Como você pode ver, a linha de comando executada é:

$ foo=$( "bash" "-c" "'echo" "hello'")

Uma aspa simples está em um lado da expresion: "'echo" , que é analisada como o comando a ser executado por bash -c e relata (corretamente) que falta uma cotação única de fechamento ''' .

Uma solução é promover a análise correta do comando com eval:

$ foo=$(eval "printf '<%s>' $cmd"); echo "$foo"
<bash><-c><echo hello>

Isso funciona:

$ foo=$(eval "$cmd"); echo "$foo"
hello

Mas a ideia correta é que: “variáveis armazenam dados, funções armazenam código” .

$ cmd(){ bash -c 'echo hello'; }
$ foo=$(cmd); echo "$foo"
hello
    
por 01.01.2016 / 21:55

Tags