119 votes

Modifier le script shell pendant son exécution

Pouvez-vous modifier un script shell pendant son exécution et que les modifications affectent le script en cours d'exécution ?

Je suis curieux du cas spécifique d'un script csh que j'ai qui lance en lot un tas de versions de construction différentes et qui s'exécute toute la nuit. Si quelque chose me vient à l'esprit en cours d'opération, j'aimerais pouvoir ajouter des commandes supplémentaires ou commenter celles qui ne sont pas exécutées.

Si ce n'est pas possible, existe-t-il un mécanisme shell ou batch qui me permettrait de le faire ?

Bien sûr, j'ai essayé, mais il faudra des heures avant que je sache si cela a fonctionné ou non, et je suis curieux de ce qui se passe ou ne se passe pas en coulisse.

3 votes

J'ai vu deux résultats en modifiant le fichier de script pour un script en cours d'exécution: 1) les modifications sont ignorées comme si elle avait lu l'intégralité dans la mémoire ou 2) le script plante avec une erreur comme s'il avait lu une partie de la commande. Je ne sais pas si cela dépend de la taille du script. De toute façon, je ne le tenterais pas.

0 votes

En bref : non, sauf s'il s'agit d'un auto-référencement / appel, auquel cas le script principal serait toujours l'ancien.

0 votes

Il y a deux questions importantes ici. 1) Comment puis-je ajouter correctement et en toute sécurité des commandes à un script en cours d'exécution? 2) Qu'arrivera-t-il lorsque je modifierai un script en cours d'exécution?

62voto

teika kazura Points 518

Cela affecte, du moins dans mon environnement bash, mais de manière très désagréable. Voyez ces codes. Tout d'abord a.sh :

#!/bin/sh

echo "Premier echo"
read y

echo "$y"

echo "C'est tout."

b.sh :

#!/bin/sh

echo "Premier echo"
read y

echo "Inséré"

echo "$y"

# echo "C'est tout."

Faire

$ cp a.sh run.sh
$ ./run.sh
$ # ouvrir un autre terminal
$ cp b.sh run.sh  # pendant que 'read' est en cours
$ # Ensuite tapez "bonjour."

Dans mon cas, la sortie est toujours :

bonjour
bonjour
C'est tout.
C'est tout.

(Bien sûr, il est bien meilleur de l'automatiser, mais l'exemple ci-dessus est lisible.)

[edit] C'est imprévisible, donc dangereux. Le meilleur contournement est , tel que décrit ici mettre le tout dans une accolade, et avant la fermeture de l'accolade, mettre "exit". Lisez bien la réponse liée pour éviter les pièges.

[ajouté] Le comportement exact dépend d'une ligne supplémentaire, et peut-être aussi de votre système Unix, du système de fichiers, etc. Si vous voulez simplement voir certaines influences, ajoutez simplement "echo foo/bar" à b.sh avant et/ou après la ligne "read".

3 votes

Mh, je ne vois pas l'affection. Est-ce que je manque quelque chose?

0 votes

Le comportement exact dépend d'une ligne supplémentaire, et peut-être aussi du système d'exploitation Unix, du système de fichiers, etc, bien que ce ne soit pas du tout certain. Si vous voulez simplement observer des influences, il vous suffit d'agrandir b.sh en ajoutant 10 lignes de echo foo/bar/baz. L'idée principale des réponses de dave4220 et de moi est que l'effet est difficile à prévoir. (Au fait, le nom "affection" signifie "amour" =)

0 votes

Oui, c'est très cassé. j'ai une solution (ci-dessous). ce qui est encore plus dangereux, ce sont les mises à jour svn/rsync/git

53voto

Erik Aronesty Points 2223

Essayez ceci... créez un fichier appelé bash-is-odd.sh:

#!/bin/bash
echo "echo yes i do odd things" >> bash-is-odd.sh

Cela démontre que bash interprète effectivement le script "au fur et à mesure". En effet, éditer un script en cours d'exécution a des résultats imprévisibles, insérant des caractères aléatoires, etc. Pourquoi ? Parce que bash lit depuis la dernière position en byte, donc l'édition déplace l'emplacement du caractère actuel en cours de lecture.

Bash est, en un mot, très, très dangereux à cause de cette "fonctionnalité". svn et rsync lorsqu'ils sont utilisés avec des scripts bash posent particulièrement problème, car par défaut ils "fusionnent" les résultats... en éditant sur place. rsync a un mode qui corrige cela. svn et git n'en ont pas.

Je présente une solution. Créez un fichier appelé /bin/bashx:

#!/bin/bash
source "$1"

Utilisez maintenant #!/bin/bashx dans vos scripts et exécutez-les toujours avec bashx au lieu de bash. Cela corrige le problème - vous pouvez synchroniser vos scripts en toute sécurité avec rsync.

Alternative (en ligne) solution proposée/testée par @AF7:

{
   # votre script
exit $?
} 

Les accolades protègent contre les modifications, et exit protège contre les ajouts. Bien sûr, nous serions tous bien mieux lotis si bash venait avec une option, comme -w (fichier entier), ou quelque chose qui ferait cela.

1 votes

Au fait; voici un plus pour contrebalancer le moins et parce que j'aime votre réponse modifiée.

2 votes

Je ne peux pas recommander cela. Dans cette solution de contournement, les paramètres de position sont décalés d'un. Rappelez-vous également que vous ne pouvez pas attribuer de valeur à $0. Cela signifie que si vous changez simplement "/bin/bash" en "/bin/bashx", de nombreux scripts échouent.

3 votes

Veuillez me dire que cette option a déjà été mise en œuvre !

18voto

glenn jackman Points 69748

Divisez votre script en fonctions, et chaque fois qu'une fonction est appelée, vous la source à partir d'un fichier séparé. Ensuite, vous pourriez modifier les fichiers à tout moment et votre script en cours d'exécution prendra en compte les modifications la prochaine fois qu'il sera sourcé.

foo() {
  source foo.sh
}
foo

0 votes

J'utilise cette technique de manière efficace depuis un certain temps maintenant pour mettre à jour mes scripts de construction en cours d'exécution. J'aimerais apprendre une technique pour amener le fichier actuel à lire jusqu'à la fin du fichier, afin de ne pas avoir à avoir deux fichiers pour implémenter chaque script shell.

1voto

dave4420 Points 31298

Je n'ai pas csh installé, mais

#!/bin/sh
echo En attente...
sleep 60
echo Le changement n'a pas eu lieu

Exécutez cela, modifiez rapidement la dernière ligne pour qu'elle dise

echo Le changement s'est produit

La sortie est

En attente...
/home/dave/tmp/change.sh: 4: Erreur de syntaxe : Chaîne non terminée

Hum.

Je suppose que les modifications apportées aux scripts shell ne prennent effet qu'une fois qu'ils sont relancés.

2 votes

Vous devez mettre la chaîne que vous voulez afficher entre guillemets.

3 votes

En fait, cela prouve que votre éditeur ne fonctionne pas comme vous le pensez. De nombreux éditeurs (y compris vim, emacs) travaillent sur un fichier "tmp", et non sur le fichier en direct. Essayez d'utiliser "echo 'echo uh oh' >> myshell.sh" au lieu de vi/emacs... et regardez comment il affiche les nouvelles infos. Pire encore... svn et rsync éditent également de cette manière!

5 votes

-1. Cette erreur n'est pas liée au fichier en cours d'édition : c'est parce que vous utilisez une apostrophe ! Cela agit comme une simple citation, provoquant l'erreur. Mettez toute cette chaîne entre guillemets doubles et réessayez.

0voto

ack Points 2273

Je n'entends pas non... mais que diriez-vous d'un peu d'indirection :

BatchRunner.sh

Command1.sh
Command2.sh

Command1.sh

runSomething

Command2.sh

runSomethingElse

Ensuite, vous devriez pouvoir éditer le contenu de chaque fichier de commande avant que BatchRunner ne le traite, n'est-ce pas ?

Ou

Une version plus propre consisterait à ce que BatchRunner regarde un seul fichier où il exécuterait consécutivement une ligne à la fois. Ensuite, vous devriez pouvoir éditer ce deuxième fichier pendant que le premier est en cours d'exécution, n'est-ce pas ?

0 votes

Je me demande s'il les charge en mémoire pour les exécuter et qu'un changement n'a plus d'importance une fois que le processus principal est initié...

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X