passando o comando de exportação para funcionar no shell script

3
#!/bin/sh

execute_cmd()
{
   $($@)
}

execute_cmd export MY_VAR=my_val
echo ${MY_VAR}

Como $() é executado em um sub-shell, $MY_VAR não está definido corretamente no shell em que o script está sendo executado.

Minha pergunta, como posso passar o comando de exportação para uma função e executá-lo no shell atual em que o script está sendo executado?

    
por user3763392 28.08.2017 / 18:51

2 respostas

1

Você deve verificar a resposta de Gilles para todos os detalhes. Em suma, você pode usar eval em vez de $() :

execute_cmd()
{
    eval "$@"
}

Em manual do bash :

eval [arguments]

The arguments are concatenated together into a single command, which is then read and executed, and its exit status returned as the exit status of eval. If there are no arguments or only empty arguments, the return status is zero.

Outros shells geralmente possuem eval embutido com semântica similar.

    
por 28.08.2017 / 18:58
5

Não está claro o que você quer fazer. $($@) não faz sentido, mas o que você quer fazer?

O que $($@) faz:

  • Pegue os argumentos da função. Esta é uma lista de strings.
  • Divida cada parte mais onde elas contêm espaço em branco¹.
  • Pegue cada parte dividida e interprete-a como um padrão curinga. Se o padrão corresponder a qualquer arquivo, substitua a peça pela lista de nomes de arquivos correspondentes.
  • Use a primeira parte como o nome de um comando para executar (função, shell embutido ou arquivo executável) e passe as outras partes como argumentos.
  • Pegue a saída do comando e divida-a onde ela contiver espaço em branco.
  • Pegue cada parte dividida e interprete-a como um padrão curinga. Se o padrão corresponder a qualquer arquivo, substitua a peça pela lista de nomes de arquivos correspondentes.
  • Use a primeira parte como o nome de um comando para executar (função, shell embutido ou arquivo executável) e passe as outras partes como argumentos.

Se isso parece complicado, é porque é.

Se você quiser que execute_cmd export MY_VAR=my_val execute export MY_VAR=my_val , por que você está incomodando com execute_cmd ?

Existem duas maneiras pelas quais isso pode ser interpretado de maneira sensata.

  1. Você deseja passar um comando com parâmetros para uma função. Um comando com parâmetros é uma lista de strings, sendo a primeira um nome de função, um shell embutido ou um arquivo executável. Em seguida, a sintaxe para invocar esse comando nos parâmetros fornecidos é "$@" .

    execute_cmd () {
      "$@"
    }
    execute_cmd export MY_VAR=my_val
    

    As aspas duplas evitam os passos de expansão de divisão e curinga que mencionei acima. Sempre use aspas duplas em torno da variável substituições .

    Observe também a natureza dupla do export keyword / builtin. Enquanto export MY_VAR=$(seq 10) trabalha na atribuição da saída de seq 10 a $MY_VAR , pois o shell analisa MY_VAR=$(seq 10) devido à presença da palavra-chave export , o shell não analisa MY_VAR=$(seq 10) como uma atribuição em execute_cmd export MY_VAR=$(seq 10) , porque o comando não é export aqui, mas execute_cmd , então MY_VAR=$(seq 10) é analisado como em qualquer argumento para qualquer comando normal e split + glob é executado em $(seq 10) , então você precisa: execute_cmd export MY_VAR="$(seq 10)" .

  2. Você deseja executar um snippet de shell. Um fragmento de shell é uma única string, a ser passada como um único argumento. Para executar uma string contendo código shell, use o eval builtin.

    execute_cmd () {
      eval "$1"
    }
    execute_cmd 'export MY_VAR=my_val'
    

¹ Assumindo o padrão IFS . Se você sabe sobre isso, não precisa ler este parágrafo.

    
por 29.08.2017 / 01:32