La commande Bash dans la chaîne s'exécute lorsque je crée la chaîne, pas lorsque je l'utilise plus tard

10

Je suis relativement nouveau dans les scripts shell, mais j'ai presque terminé un script qui utilise le programme lftp . La partie du script qui me pose problème est lorsque je crée une longue chaîne de commandes (séparées par ;).

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

Ce que je remarque, c'est que le tailprogramme - enveloppé dans les backticks - est exécuté lorsque la boucle for est en cours d'itération, mais pas lorsque j'appelle la chaîne de commandes plus tard dans mon script.

Malheureusement, le contenu de $ somefile n'est pas à ce stade prêt à être inspecté. Comment puis-je obtenir l'exécution de la commande lorsque j'en ai besoin, et non pendant que je crée la chaîne?

Ricky
la source

Réponses:

8

Celui-ci est un peu délicat. Les informations fournies par Hauke ​​sont correctes, il s'agit simplement de les analyser pour votre cas d'utilisation.

La manière la plus simple consiste à utiliser la $()syntaxe tout en échappant à la $telle que la définition de variable n'exécute pas la commande incluse par le $()au moment de la définition. La mise en garde est que le résultat final doit ensuite être réévalué (via eval) par le shell au moment de l'exécution réelle pour que la commande imbriquée s'exécute.

Il est beaucoup plus facile de regarder un exemple, alors prenez celui-ci, qui devrait vous mettre sur la bonne voie:

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

Voici un exemple de sortie de l'exemple ci-dessus (réduit à une itération):

1398832186.133661344
1398832187.139076728

Vous remarquerez que le deuxième horodatage pour chaque boucle est environ une seconde après la première. Inversement, si vous effectuez le même test sans échapper $à la testdéfinition et supprimer le eval, les deux horodatages correspondront presque.

Ne prenez pas l'habitude de l'utiliser evaldans la plupart des situations, mais c'est une de celles où je ne connais pas de bonne façon de l'éviter. J'espère que cela aide. Bonne chance!

daBeamer
la source
Merci beaucoup, j'ai essayé d'utiliser $(...)comme Hauke ​​l'a suggéré mais la barre oblique inverse est la clé.
Ricky
Heureux que cela ait aidé - rappelez-vous, cependant, la clé ici est vraiment evalcar vous pouvez faire la même chose en n'échappant pas à la $et en utilisant des guillemets simples ( ') plutôt que des guillemets doubles ( ") pour entourer votre commande.
daBeamer
Maintenant, je viens de réaliser, tout comme avec les suggestions de Huake, une fois que j'essaie d'utiliser ceci dans le programme lftp, l'écho imprime simplement la commande, il ne l'exécutera pas réellement. Pourrait avoir à essayer leur liste de diffusion pour une aide plus spécifique.
Ricky
Quelle commande essayez-vous d'exécuter? J'avais l'impression que vous vouliez echoune chaîne avec un contenu incluant la sortie d'une commande imbriquée à exécution différée.
daBeamer
1
@Ricky Je serais d'accord avec tous les points de @HaukeLaging. Le code en l'état moins le echone fonctionnera pas car il n'y a pas de commande eval, mais plutôt une chaîne. Si vous avez un exemple plus pertinent pour nous, nous pouvons essayer de vous aider.
daBeamer
6

Il existe plusieurs niveaux de cotation. Les guillemets doubles ( "...") sauvegardent les espaces et plusieurs caractères spéciaux ( ~, &, |, ;, ...) mais n'empêche pas l' expansion et la substitution de commande paramètre.

Vous avez besoin de guillemets simples ( ') ou d'une barre oblique inverse devant les caractères "dangereux".

En général: vous devriez envisager d'utiliser $(tail ...)plutôt que des crochets. Les backticks sont la norme la plus ancienne mais nous parlons de si vieux qui $()ne causent pas de problèmes à la plupart des gens. La nouvelle version est plus facile à lire et peut être imbriquée. Sans parler des problèmes de formatage ici sur sx ...

Hauke ​​Laging
la source
Merci pour la réponse rapide Hauke. Malheureusement, le remplacement des backticks par le recommandé $(...)produit toujours le même résultat - le shell l'exécute lorsque ma chaîne est définie.
Ricky
@Ricky Ce n'étaient pas des suggestions alternatives. Vous devez utiliser $()mais vous avez quand même besoin des guillemets simples.
Hauke ​​Laging du
Donc, aucune combinaison de ces personnages n'atteindra ce que je recherche?
Ricky
@Ricky Qu'est-ce qui est si difficile à comprendre à propos de "Vous avez besoin de guillemets simples"? De toute évidence, vous n'essayez même pas.
Hauke ​​Laging du
En fait, je l'ai fait, mais lorsque j'utilise des guillemets simples, l'écho affichera simplement tout sur cette ligne comme une chaîne normale. Pourquoi est-il si difficile de donner un exemple?
Ricky