O comando bash na string está em execução quando eu crio a string, não quando eu a uso mais tarde

10

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

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

O que estou notando é que o tailprograma - envolvido nos backticks - está sendo executado quando o loop for está repetindo, mas não quando invoco a sequência de comandos posteriormente no meu script.

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

Ricky
fonte

Respostas:

8

Este é um pouco complicado. As informações que a Hauke ​​forneceu estão corretas, é apenas uma questão de analisá-las para o seu caso de uso.

A maneira mais fácil é usar a $()sintaxe ao escapar da $tal que a definição da variável não executa o comando incluído 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 que o comando aninhado seja executado.

É muito mais fácil olhar para um exemplo, então pegue este, 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

Aqui está um exemplo de saída do exemplo acima (aparado em uma iteração):

1398832186.133661344
1398832187.139076728

Você notará que o segundo registro de data e hora para cada loop é cerca de um segundo após o primeiro. Por outro lado, se você executar o mesmo teste sem escapar o $na testdefinição e removendo o eval, os dois timestamps irá quase igualar.

Não use o hábito de usar evalna maioria das situações, mas esse é um daqueles onde não conheço uma boa maneira de evitá-lo. Espero que isso ajude. Boa sorte!

daBeamer
fonte
Muito obrigado, tentei usar $(...)como Hauke ​​sugeriu, mas a barra invertida é a chave.
217 Ricky
Que bom que ajudou - lembre-se, porém, a chave aqui realmente é evalque você pode fazer a mesma coisa, não escapando de $e usando aspas simples ( ') em vez de aspas duplas ( ") para cercar seu comando.
DaBeamer
Agora eu acabei de perceber, assim como as sugestões de Huake, uma vez que tento usar isso no programa lftp, o eco simplesmente imprime o comando, na verdade não o executa. Pode ser necessário tentar a lista de discussão para obter ajuda mais específica.
Ricky
Que comando é esse que você está tentando executar? Fiquei com a impressão de que você queria echouma string com conteúdo, incluindo a saída de um comando aninhado de execução atrasada.
DaBeamer
1
@ Ricky Eu teria que concordar com todos os pontos do @HaukeLaging. O código como está menos o que echonão vai funcionar porque não há nenhum comando para eval, mas uma string. Se você tem um exemplo mais pertinente para nós, podemos tentar ajudar.
DaBeamer
6

Existem vários níveis de cotação. Aspas ( "...") espaços em branco de proteção e vários caracteres especiais ( ~, &, |, ;, ...), mas não impede expansão de parâmetros e substituição de comando.

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

Em geral: você deve considerar usar, em $(tail ...)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 no sx ...

Hauke ​​Laging
fonte
Obrigado pela resposta rápida Hauke. Infelizmente, a substituição dos backticks pelos recomendados $(...)ainda produz o mesmo resultado - o shell executa isso quando minha string é definida.
21714 Ricky
@ Ricky Isso não eram sugestões alternativas. Você deve usar, $()mas precisa de aspas simples de qualquer maneira.
Hauke ​​Laging
Então, nenhuma combinação desses personagens vai conseguir o que eu estou procurando?
Ricky
@ Ricky O que é tão difícil de entender sobre "Você precisa de aspas simples"? Você obviamente nem tenta.
Hauke ​​Laging
Na verdade, sim, mas quando uso aspas simples, o eco apenas imprime tudo nessa linha como uma sequência normal. O que há de tão difícil em fornecer um exemplo?
RickyRicky