Substituindo nomes de variáveis de shell em outra variável

1

Eu tenho lutado com bash substituição de variável por um tempo agora e não consigo descobrir isso ...

Eu tenho uma variável com um modelo de comando:

CMD_TMPL='sudo -u ${USER_NAME} ${USER_HOME}/script.sh'

As variáveis USER_NAME e USER_HOME são calculadas posteriormente no script, ainda não conhecidas no momento em que CMD_TMPL é definido. Portanto, o comando está entre aspas simples e ainda não está substituído.

Em seguida, o script calcula USER_NAME=test e USER_HOME=/home/test e eu quero fazer algo que leve a ${CMD} contendo:

sudo -u test /home/test/script.sh

Mais abaixo no script eu vou usar esse comando em um pipe como:

${CMD} | output-processing.sh

Como obtenho a expansão dos nomes de variáveis em ${CMD_TMPL} para valores de variáveis em ${CMD} ? Eu tentei todos os tipos de echo e eval , mas não consigo descobrir.

Obrigado!

    
por MLu 11.08.2014 / 08:18

1 resposta

6

Há um tipo especial de variável que é usado para armazenar código, isso é funções :

cmd_tmpl() { sudo -u "$USER_NAME" "$USER_HOME/script.sh" "$@"; }
cmd() { cmd_tmpl other args "$@"; }
cmd | output_processing...

As outras abordagens são para considerar as variáveis como linhas de comando (código shell) e interpretar esse código no final usando eval :

cmd_tmpl='sudo -u "$USER_NAME" "$USER_HOME/script.sh"'
cmd=$cmd_tmpl' other args as shell code'
eval "$cmd" | output_processing...

Usar $cmd | output_processing está errado. $cmd é uma variável escalar e você está usando o operador split + glob para obter a lista de argumentos para um comando simples, você não está avaliando a linha de comando armazenada nela. Então, isso só funciona em um conjunto restrito de condições.

Você pode armazenar argumentos em um comando simples em uma matriz:

cmd=(sudo -u "$USER_NAME" "$USER_HOME/script.sh" ...)
"${cmd[@]}" | post_processing

mas isso não ajudará na expansão adiada de suas variáveis.

Você pode adiar a expansão com coisas como:

cmd_tmpl='sudo -u "$USER_NAME" "$USER_HOME/script.sh"'
...
eval "cmd=($cmd_tmpl)" # now expanded
cmd+=(other args)
"${cmd[@]}" | post-processing

(observe que é uma boa prática reservar nomes de variáveis com todas as letras maiúsculas para variáveis exportadas para o ambiente).

    
por 11.08.2014 / 08:46