O comando Bash na string está sendo executado quando eu crio a string, não quando eu a uso mais tarde

10

Sou relativamente novo no shell de scripts, mas quase concluí um script que faz uso do programa lftp . A parte do script que estou tendo problemas é quando eu crio uma longa seqüência de comandos (separados por ; ).

for var in something
do
    ...
    commands_to_run+="echo Result is 'tail -n 1 $somefile';"
done

O que eu estou percebendo é que o programa tail - envolvido nos backticks - está sendo executado quando o loop for está iterando, mas não quando invoco a sequência de comandos mais tarde no meu script.

Infelizmente, o conteúdo de $ somefile não está pronto para ser inspecionado. Como posso obter o comando para executar quando preciso, e não enquanto estou criando a string?

    
por Ricky 30.04.2014 / 01:14

2 respostas

7

Este é um pouco complicado. A informação que Hauke forneceu está correta, é apenas uma questão de analisá-la para o seu caso de uso.

A maneira mais fácil é usar a sintaxe $() ao escapar do $ , de modo que a definição da variável não execute o comando delimitado pelo $() no momento da definição. A ressalva é que o resultado final deve ser reavaliado (via eval ) pelo shell no momento da execução real para o comando aninhado executar.

É muito mais fácil analisar um exemplo, por isso, tome este, o que deve colocá-lo no caminho certo:

for((i=0;i<10;i++)); do 
  date +%s.%N  # Print a timestamp (in format seconds.nanoseconds)
  test="echo \$(date +%s.%N)" # Save a command to do the same
  sleep 1      # Sleep for a second
  eval "$test" # Evaluate the command saved in variable 'test'
  echo         # Print a new line before the next iteration
done

Veja a saída de amostra do exemplo acima (aparada em uma iteração):

1398832186.133661344
1398832187.139076728

Você notará que o segundo timestamp de cada loop é de cerca de um segundo após o primeiro. Por outro lado, se você realizar o mesmo teste sem escapar do $ na definição test e remover o eval , os dois carimbos de data / hora quase corresponderão.

Não adquira o hábito de usar eval na maioria das situações, mas esse é um daqueles em que não sei como evitá-lo. Espero que isso ajude. Boa sorte!

    
por 30.04.2014 / 06:36
6

Existem vários níveis de cotação. Aspas duplas ( "..." ) protegem o espaço em branco e vários caracteres especiais ( ~ , & , | , ; , ...), mas não impedem a expansão de parâmetros e a substituição de comandos.

Você precisa de aspas simples ( ' ) ou uma barra invertida na frente dos caracteres "perigosos".

Em geral: Você deve considerar usar $(tail ...) em vez de backticks. Backticks são o padrão mais antigo, mas estamos falando de algo tão antigo que $() não causa problemas para a maioria das pessoas. A nova versão é mais fácil de ler e pode ser aninhada. Muito menos os problemas de formatação aqui em sx ...

    
por 30.04.2014 / 01:36