Modification script shell

gerard -  
Hxyp Messages postés 401 Date d'inscription   Statut Membre Dernière intervention   -
bonjour, j'ai le script shell suivant que j'ai écrit:
for i in 1 2 3 
do 

if [ $1 = "x" ] 
then 
 FILE=$1.sync 
 echo > $FILE 
fi 

while [ ! -f $FILE ] 
do 
sleep 1 
done 

echo $1 : $i 
rm -f $FILE 
done


Je souhaite le modifier pour que quand je tape ça dans mon shell:
./script x & ./script y &
il m'affiche ALTERNATIVEMENT x : 1 , y : 1 , x : 2 , y : 2...

Quelqu'un saurait me filer un coup de main car personne ne sait depuis des jours et des jours..
merci
A voir également:

21 réponses

Hxyp Messages postés 401 Date d'inscription   Statut Membre Dernière intervention   54
 
Bonjour,
En ajoutant un sleep ça fonctionne avec ./sr.sh x & ./sr.sh y & ./sr.sh z . . . .. :
for i in 1 2 3 
do 
        if [ "$1" = "x" ] 
        then 
                FILE=$1.sync 
                echo > $FILE 
        fi 
while [ ! -f $FILE ] 
do 
        sleep 1 
done 

echo $1 : $i 
rm -f $FILE 
sleep 0.01 
done 

Edit: petite modification du sleep que j'ai rajouté, viens juste d'apprendre qu'on peut utiliser moins d'une seconde
Edit²: Ouais non en fait le sleep plus il est long mieux ça fonctionnera, quand je test avec la même valeur 0.01 et que j'ajoute une commande supplémentaire ça déraille, en augmentant le sleep ça fix le problème
0
gerard
 
salut HXYP, non j'avais déjà essayé de rajouter un sleep exactement au même endroit que toi mais ça ne fonctionne pas, en fait a fonctionne à 90% mais pas à 100% car rien n'empêche à un processus d'afficher 2 fois x :1 x : 2, essaye tu verras :-).
Donc le fait de rajouter un sleep à mon grand désarroi ne change rien...
0
Hxyp Messages postés 401 Date d'inscription   Statut Membre Dernière intervention   54
 
Re, je pense avoir trouvé un début de réponse ou peut-être la réponse ? en utilisant le C car on peut exécuter des commandes avec et gérer l'ordre. Alors voici un petit code en c :
en commentaire j'ai mis la référence du bout de code que j'ai pompé et modifié pour qu'on puisse faire une boucle en fonction des paramètres... j'explique un peu plus bas

//https://stackoverflow.com/questions/646241/c-run-a-system-command-and-get-output
#include <stdio.h>
#include <stdlib.h>

int main(int argc,char *argv[])
  {
    FILE *fp;
    char path[1035];
    int i, a, x=atoi(argv[1]);
    for(a=0;a<x;a++)
      {
        for(i=2;i<argc;i++)
          {
            fp=popen(argv[i],"r");
            if(fp==NULL)
              {
                fprintf(stderr,"Erreur popen()\n");
                exit(1);
              }
            while(fgets(path,sizeof(path),fp) != NULL)
              {
                printf("%s",path);
              }
            pclose(fp);
          }
      }
    return 0;
  }


Pour compiler tu peux faire :
gcc -Wall -o prog prog.c

Pour l'utiliser :
./prog 3 "echo x" "echo y"

le premier paramètre le 3 pour l'exemple c'est le nombre de répétitions : les commandes qui suivent seront alors exécutées à la suite le nombre de fois indiqué dans le premier param!

le résultat :
x
y
x
y
x
y

Faut pas oublier de mettre les commandes entre des guillemets
0
gerard
 
l'exercice est uniquement à faire en sh lol, j'ai tenté de poser des verrous avec lockfile mais ça n'a pas marché, si jamais un connaisseur du sh passe par là qu'il se manifeste car tout le monde se casse les dents dessus lol.
Merci Hxyp pour ces tentatives :-(
0
Hxyp Messages postés 401 Date d'inscription   Statut Membre Dernière intervention   54
 
Je n'avais pas imaginé que c'était un exercice, heu sinon bah hm il faudrait voir au niveau des id car lorsqu'on démarre une list avec & il affiche le premier job [1] (on peut récupérer l'id courant avec $!) et l'id du dernier processus dans la list, j'ai testé en faisant :
#!/bin/bash
set -m
for i in 1 2 3
do
    echo $1 : $i
    suspend $!
done

mais pas réussi à "resume" avec "bg %-" qui semble ne fonctionner qu'en mode interactif bien que j'ai utilisé "set -m" dans le script.
Faites le test, le script va suspendre chaque job (on peut les voir en utilisant la commande "jobs") puis les remettre en route en répétant la commande "bg %-" à la main c'est cette action que je ne sais pas comment la mettre dans le script.

quels liens la dessus :
https://pubs.opengroup.org/onlinepubs/009695399/utilities/xcu_chap02.html#tag_02_09_03_02
http://www.gnu.org/savannah-checkouts/gnu/bash/manual/bash.html#Job-Control
https://www.linuxtopia.org/online_books/advanced_bash_scripting_guide/x6632.html
https://ss64.com/bash/syntax-jobs.html
0
Char Snipeur Messages postés 9813 Date d'inscription   Statut Contributeur Dernière intervention   1 299
 
help suspend te dit que tu peux continuer un processus en envoyant le signal SIGCONT. Tu peux alors envoyer un signal avec "kill".
essai "kill -s SIGCONT %-"
0
Hxyp Messages postés 401 Date d'inscription   Statut Membre Dernière intervention   54
 
Merci pour l'aide j'ai pu continué mais il y a un problème que je ne comprend pas sur mon script, le suspend créé un logout et donc ça ferme mon shell à chaque fois, et je ne peux pas voir le résultat !

#!/bin/bash
set -m
vid=""
sta=0
sto=0

function get_list
{
    get='ps | grep ${0##*/} | gawk '{ printf $1 " " }''
}
function v_id
{
    get_list
    #vid='echo $get | gawk -v var=$$ '{ for(j=1;j<NF+1;j++){ if($j == var) printf var } }''
    vid='echo $get | gawk -v var=$$ -v stt=$sto '{ for(i=1;i<NF+1&&NF>1;i++){ if($i==var&&i!=NF&&i>1&&stt==1) printf $((i+1)); if(i==NF&&$i==var) printf $1 } }''
    sta='echo $get | gawk -v var=$$ '{ for(i=1;i<NF+1;i++){ if($i==var&&i==NF) printf 1 } }''
}
for i in 1 2 3
do
    v_id
    echo $vid
    if [ $sto ] && [ $sta ]
    then
        kill -s CONT $vid
    fi
    echo $1 : $i : $$
    sto=1
    suspend $!
done
#exit 0

C'est un peu spaghetti, l'idée est de lister tout les id avec soit "ps" ou "jobs -l" et de récupérer la liste des id avec awk en fonction du nom du script "${0##*/} et d'alterner avec CONT et suspend sur la liste en fonction de leur position vu qu'ils se lancent en incrémentant le numéro de l'id c'est dans l'ordre mais je bug là... j'apprends tout juste le bash scripting (là en fait)
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
Char Snipeur Messages postés 9813 Date d'inscription   Statut Contributeur Dernière intervention   1 299
 
Salut.
en fait, c'est assez simple en modifiant le script pour vérifier les pichier .sync
for i in 1 2 3 
do 

  FILE=$1.sync 
  echo $i> $FILE 
  
  echo $1 : $i 
  rm -f $FILE 
  test=0
  while $test
  do :
      for a in $(ls *.sync)
      do :
          if  [ $i <= $(cat $a) ]
             test=1
          fi
      done
      sleep 1
  done

done

Je n'ai pas testé, mais tu vois l'idée ? tu stockes dans le fichier le nombre courant, tant que ce nombre est supérieur à ceux des autres scripts, tu attends. ça garantie d'avoir 1 puis 2 puis 3.
si tu veux aficher x y z dans cet ordre, c'est faisable avec un classement par ordre alphabétique des fichier : tant qu'il y a une lettre avant le script en court ne rien faire.
Si l'affichage doit se faire selon l'ordre de lancement des scripts, je pense que c'est impossible à réaliser.
0
gerard
 
je vais tester, en fait l'exercice c'est ça, soit le script suivant:

for i in 1 2 3
do
echo $1 : $i
done

modifier ce script pour que lors de la commande ./script.sh x & ./script.sh y & on ait un affichage alternatif parfait:

x: 1
y: 1
x: 2
y: 2
x: 3
y: 3
0
gerard
 
alors j'ai testé ton script et ton algorithme me semble pas mal, je voulais faire ça au début mais bon, ton script m'affiche:

y : 1
x : 1

et ensuite un défilement du message ls: ne peut accéder *.sync: Aucun fichier ou dossier de ce type. impossible à arrêter meme avec un ctrl+c ...
Même en déplaçant l'instruction rm -f $FILE après la boucle while ça ne change rien, bizarre.
0
Char Snipeur Messages postés 9813 Date d'inscription   Statut Contributeur Dernière intervention   1 299
 
oui, je m'en doutais que ça ne fonctionnerai pas aussi simplement. Il faut rajouter un if avant le for, pour vérifier qu'il existe bien un fichier .sync. S'il n'y en a pas, tu peux alors bouclé.
Je pense aussi qu'il faut déplacer le rm à la fin.
Après ça devrais aller mieux.
0
gerard
 
alors regarde j'ai modifié le script mais ça marche tjs pas et d'ailleurs je trouve bizarre qu'on doive vérifier que le fichier .sync existe puisque de toute manière il existe avant d'entrer dans la boucle si on met le rm -f $FILE à la fin, voici le script:

#! /bin/bash

for i in 1 2 3 
do 

  FILE=$1.sync 
  echo $i> $FILE 
  echo $1 : $i 
  test=0
  while [ $test ]
  do
     if [ -f $FILE ]
     then
      for x in 'ls *.sync'
      do
          if  [ $i <= 'cat $x' ]
	  then
             test=1
          fi
      done
      else
      sleep 1
      fi
  done
rm -f $FILE
done


c'est cette ligne if [ $i <= 'cat $x' ] qui pose problème même avec ton script...
0
Char Snipeur Messages postés 9813 Date d'inscription   Statut Contributeur Dernière intervention   1 299
 
essai if [ $i -le $(cat $x) ] ou alors carément : if (( $i <= $(cat $x) ))
0
gerard
 
non ya rien à faire, je me demande finalement si l'idée est bonne car rien n'empêche ton algorithme d'afficher:

a: 1
a: 2
...

bref ça ne fonctionne tjs pas et on est plusieurs à y avoir réfléchi c'est incroyable qu'un exercice si court nous demande tant de reflexion ça doit pas etre sorcier pourtant....

Personne connait un expert en sh? lol
0
Char Snipeur Messages postés 9813 Date d'inscription   Statut Contributeur Dernière intervention   1 299
 
là c'est pas de l'expertise en sh qu'il faut, c'est un bon algoritmhe.
Je me suis d'ailleur rendu compte que mon algo été mauvais.
Je regarde si un seul fichier vaut au moins $i, alors qu'il faudrait tout les regardé.
C'est tout con, mais j'ai un peu de mal à l'écrire cet algo.
0
Char Snipeur Messages postés 9813 Date d'inscription   Statut Contributeur Dernière intervention   1 299
 
#! /bin/bash

FILE=$1.sync 
touch  $FILE
# on attend un peu que tout les scripts créent leur fichier
sleep 10

#on compte le nombre de script
nbs=$(ls *.sync|wc -l)

for i in 1 2 3 
do 
  echo $i> $FILE 
  echo $1 : $i 
  test=0
#tant que tout les scripts n'ont pas atteints la valeur en cour
  while [ $test -lt $nbs ]
  do
      test=0
      for x in 'ls *.sync'
      do
          if  [ $i <= 'cat $x' ]
	  then
             (( test++ )
          fi
      done
      sleep 1
  done
#mieu vaut ecraser que supprimer
#rm -f $FILE
done
0
gerard
 
non ça ne marche pas, et cela me semble bien trop volumineux pour ce qui est demandé, je crois que je vais abandonné cet exercice tant pis, merci pour tes réflexions c'est sympa.
0
gerard
 
sinon à tout hasard dans mon script de départ:
for i in 1 2 3 
do 

if [ $1 = "x" ] 
then 
 FILE=$1.sync 
 echo > $FILE 
fi 

while [ ! -f $FILE ] 
do 
sleep 1 
done 

echo $1 : $i 
rm -f $FILE 
done


as tu une petite idée pour juste forcer le premier affichage à être x : 1 ?
0
zipe31 Messages postés 36402 Date d'inscription   Statut Contributeur Dernière intervention   6 431
 
Salut,

$ cat foo.sh
#! /bin/bash

#set -xv

for i in 1 2 3
do
        echo $1 : $i
        sleep 1
done

$ ./foo.sh x& ./foo.sh y
x : 1
[1] 25503
y : 1
x : 2
y : 2
x : 3
y : 3
[1]+  Done                    ./foo.sh x
$


A part le PID du job en arrière-plan qui vient s'intercaler, le résultat me semble bon, non ?
0
zipe31 Messages postés 36402 Date d'inscription   Statut Contributeur Dernière intervention   6 431
 
Pour un affichage plus conforme :

$ ./foo.sh x | tee -a log& ./foo.sh y | tee -a log
[1] 25765
x : 1
y : 1
x : 2
y : 2
x : 3
y : 3
[1]+  Done                    ./foo.sh x | tee -a log

$ cat log
x : 1
y : 1
x : 2
y : 2
x : 3
y : 3
$

;-))
0
gerard
 
non zipe ta solution marche pas je l'avais déjà essayé tout au début, si tu fais 10 essais tu verras que à un moment tu auras 2 x ou 2 y qui se suivent.

voici la preuve:

image x : 1 s'affiche, tu commutes donc y : 1 s'affiche ok? mais rien n'empêche le processus y de continuer par la suite...il y a d'autres commutations aléatoires produites par l'ordonnanceur.

Donc malheureusement je suis pas le seul à bloquer sur ce petit exercice...
0
zipe31 Messages postés 36402 Date d'inscription   Statut Contributeur Dernière intervention   6 431
 
$ cat foo.sh
#! /bin/bash

#set -xv

for i in {1..10}
do
        echo $1 : $i
        sleep 1
done

$ ./foo.sh x | tee -a log& ./foo.sh y | tee -a log
x : 1
[1] 27445
y : 1
x : 2
y : 2
x : 3
y : 3
x : 4
y : 4
x : 5
y : 5
x : 6
y : 6
x : 7
y : 7
x : 8
y : 8
x : 9
y : 9
x : 10
y : 10
[1]+  Done                    ./foo.sh x | tee -a log

$ cat log
x : 1
y : 1
x : 2
y : 2
x : 3
y : 3
x : 4
y : 4
x : 5
y : 5
x : 6
y : 6
x : 7
y : 7
x : 8
y : 8
x : 9
y : 9
x : 10
y : 10
$

Désolé ;-))
0
gerard
 
zipe tu es vraiment chanceux mais je t'assure que ton script ne fonctionne pas je l'ai testé des dizaines de fois et ya tjs une erreur tôt ou tard, j'ai donné la preuve théorique il me semble...
crois moi j'aurais aimé que tu aies raison :'(
0
zipe31 Messages postés 36402 Date d'inscription   Statut Contributeur Dernière intervention   6 431
 
Dois-je m'inquiéter d'être aussi chanceux ? ;-))

$ cat foo.sh
#! /bin/bash

#set -xv

for i in {1..50}
do
        echo -e "$1 : $i, \c"
        sleep 1
done

$ ./foo.sh x | tee -a log& ./foo.sh y | tee -a log
x : 1, [1] 29041
y : 1, x : 2, y : 2, x : 3, y : 3, x : 4, y : 4, x : 5, y : 5, x : 6, y : 6, x : 7, y : 7, x : 8, y : 8, x : 9, y : 9, x : 10, y : 10, x : 11, y : 11, x : 12, y : 12, x : 13, y : 13, x : 14, y : 14, x : 15, y : 15, x : 16, y : 16, x : 17, y : 17, x : 18, y : 18, x : 19, y : 19, x : 20, y : 20, x : 21, y : 21, x : 22, y : 22, x : 23, y : 23, x : 24, y : 24, x : 25, y : 25, x : 26, y : 26, x : 27, y : 27, x : 28, y : 28, x : 29, y : 29, x : 30, y : 30, x : 31, y : 31, x : 32, y : 32, x : 33, y : 33, x : 34, y : 34, x : 35, y : 35, x : 36, y : 36, x : 37, y : 37, x : 38, y : 38, x : 39, y : 39, x : 40, y : 40, x : 41, y : 41, x : 42, y : 42, x : 43, y : 43, x : 44, y : 44, x : 45, y : 45, x : 46, y : 46, x : 47, y : 47, x : 48, y : 48, x : 49, y : 49, x : 50, y : 50, [1]+  Done                    ./foo.sh x | tee -a log

$ cat log
x : 1, y : 1, x : 2, y : 2, x : 3, y : 3, x : 4, y : 4, x : 5, y : 5, x : 6, y : 6, x : 7, y : 7, x : 8, y : 8, x : 9, y : 9, x : 10, y : 10, x : 11, y : 11, x : 12, y : 12, x : 13, y : 13, x : 14, y : 14, x : 15, y : 15, x : 16, y : 16, x : 17, y : 17, x : 18, y : 18, x : 19, y : 19, x : 20, y : 20, x : 21, y : 21, x : 22, y : 22, x : 23, y : 23, x : 24, y : 24, x : 25, y : 25, x : 26, y : 26, x : 27, y : 27, x : 28, y : 28, x : 29, y : 29, x : 30, y : 30, x : 31, y : 31, x : 32, y : 32, x : 33, y : 33, x : 34, y : 34, x : 35, y : 35, x : 36, y : 36, x : 37, y : 37, x : 38, y : 38, x : 39, y : 39, x : 40, y : 40, x : 41, y : 41, x : 42, y : 42, x : 43, y : 43, x : 44, y : 44, x : 45, y : 45, x : 46, y : 46, x : 47, y : 47, x : 48, y : 48, x : 49, y : 49, x : 50, y : 50, $
$

;-))
0
gerard
 
alors mon ami zipe voici le preuve que tu es chanceux et je te conseille tout de suite d'aller t'acheter un billet de loto, j'ai testé ton script donc celui ci:
#! /bin/bash 

for i in 1 2 3 
do 
        echo $1 : $i 
        sleep 1 
done


et voici ce que j'ai dans le shell, observe bien l'erreur arrive à la fin :-)
-VirtualBox:~/TEST$ ./toto.sh a & ./toto.sh b & 
[1] 1884 
[2] 1885 
-VirtualBox:~/TEST$ b : 1 
a : 1 
b : 2 
a : 2 
b : 3 
a : 3 

[1]-  Done                    ./toto.sh a 
[2]+  Done                    ./toto.sh b 
-VirtualBox:~/TEST$ ./toto.sh a & ./toto.sh b & 
[1] 1892 
[2] 1893 
-VirtualBox:~/TEST$ a : 1 
b : 1 
a : 2 
b : 2 
a : 3 
b : 3 

[1]-  Done                    ./toto.sh a 
[2]+  Done                    ./toto.sh b 
-VirtualBox:~/TEST$ ./toto.sh a & ./toto.sh b & 
[1] 1900 
[2] 1901 
-VirtualBox:~/TEST$ b : 1 
a : 1 
b : 2 
a : 2 
b : 3 
a : 3 

[1]-  Done                    ./toto.sh a 
[2]+  Done                    ./toto.sh b 
-VirtualBox:~/TEST$ ./toto.sh a & ./toto.sh b & 
[1] 1908 
[2] 1909 
-VirtualBox:~/TEST$ b : 1 
a : 1 
b : 2 
a : 2 
b : 3 
a : 3 

[1]-  Done                    ./toto.sh a 
[2]+  Done                    ./toto.sh b 
-VirtualBox:~/TEST$ ./toto.sh a & ./toto.sh b & 
[1] 1916 
[2] 1917 
-VirtualBox:~/TEST$ a : 1 
b : 1 
a : 2 
b : 2 
a : 3 
b : 3 

[1]-  Done                    ./toto.sh a 
[2]+  Done                    ./toto.sh b 
-VirtualBox:~/TEST$ ./toto.sh a & ./toto.sh b & 
[1] 1924 
[2] 1925 
-VirtualBox:~/TEST$ b : 1 
a : 1 
b : 2 
a : 2 
b : 3 
a : 3 

[1]-  Done                    ./toto.sh a 
[2]+  Done                    ./toto.sh b 
-VirtualBox:~/TEST$ ./toto.sh a & ./toto.sh b & 
[1] 1932 
[2] 1933 
-VirtualBox:~/TEST$ b : 1 
a : 1 
b : 2 
a : 2 
b : 3 
a : 3 

[1]-  Done                    ./toto.sh a 
[2]+  Done                    ./toto.sh b 
-VirtualBox:~/TEST$ ./toto.sh a & ./toto.sh b & 
[1] 1940 
[2] 1941 
-VirtualBox:~/TEST$ a : 1 
b : 1 
a : 2 
b : 2 
b : 3 
a : 3 
0
zipe31 Messages postés 36402 Date d'inscription   Statut Contributeur Dernière intervention   6 431
 
Pourquoi lances-tu le second script en arrière-plan ?
Le 1er je veux bien, mais le second ce n'est pas la peine... si ?
0
gerard
 
et bien si c'est obligatoire lol
0
Char Snipeur Messages postés 9813 Date d'inscription   Statut Contributeur Dernière intervention   1 299
 
je suis plutôt d'accord avec gerard, rien ne garantit l'ordre d'exécution.
Si c'est un exercice, j'aimerai bien connaitre la solution, car pour moi c'est impossible ou très compliqué d'avoir ce que tu veux exactement.
0
gerard
 
l'exercice en lui même est très simple, j'ai ce script de départ:
for i in 1 2 3 
do 
echo $1 : $i 
done 


A l'exécution de cette commande: ./script.sh x & ./script.sh y & il faut que chaque processus fasse son affichage en alternant obligatoirement, donc l'ordre doit etre ici x y x y x y ou y x y x y x.

Je sais qu'il faut utiliser la synchronisation et la protection des sections critiques (genre lockfile), mais malgré des dizaines d'essais, nada. C'est du parallélisme et oui c'est difficile.
0
zipe31 Messages postés 36402 Date d'inscription   Statut Contributeur Dernière intervention   6 431
 
Tiens essaie ça :

#! /bin/bash

#set -xv

for i in {1..50}
do
        while :
        do
                if [ -e lock.tmp ]
                then continue
                else
                        echo "$1 : $i"
                        touch lock.tmp
                        sleep 1
                        rm -f lock.tmp
                        break
                fi
        done
done
0
gerard
 
je ne comprends pas ton while : (jamais vu) et je n'ai pas encore vu l'instruction lock, les seules choses dont j'ai le droit c'est le lockfile et un fichier de synchronisation, on ma dit que c'était ça la clef..
0
zipe31 Messages postés 36402 Date d'inscription   Statut Contributeur Dernière intervention   6 431
 
while : = while true
Tant que la condition est vraie.

et je n'ai pas encore vu l'instruction lock, les seules choses dont j'ai le droit c'est le lockfile
Ben en fait le "touch lock.tmp" ne fait que creer un fichier nommé "lock.tmp" ;-)
0
gerard
 
j'ai testé le script et échec du premier coup lol, c'est pas évident je sais...
0
zipe31 Messages postés 36402 Date d'inscription   Statut Contributeur Dernière intervention   6 431
 
Ben faut croire que t'as la scoumoune ;-((
0
Char Snipeur Messages postés 9813 Date d'inscription   Statut Contributeur Dernière intervention   1 299
 
zipe, fait un man lockfile
0