View previous topic :: View next topic |
Author |
Message |
George Abitbol n00b
Joined: 02 Feb 2006 Posts: 55
|
Posted: Wed Apr 04, 2007 9:21 am Post subject: [bash] addition, for, while, visibilité de variable (Résol |
|
|
Bonjour,
je voudrais faire un script qui :
- lit un fichier de plusieurs lignes dont les champs sont séparés par des espaces
- fais un total des 5è champs de toutes les lignes
- affiche le résultat
j'ai donc fait ça :
Code: |
#!/bin/bash
# count.sh
total=0
erreur () {
echo -e "usage : \n\t$0 file\n"
exit
}
[[ $# == 1 ]] || erreur
echo -e "Processing file ${1}\n"
cat $1 | while read line ;
do
size=`echo $line | cut -d ' ' -f 5`
total=$(( $total + $size ))
done
echo -e "Total : ${total}\n"
echo -e "-- Exit --"
exit 0
|
Le hic, c'est que mon compte à l'air de se faire dans le process while, du coup à la fin de la boucle le résultat est perdu.
J'ai essayé avec un for en bricolant $IFS, mais ça a rien donné.
Est-ce que quelqu'un saurait comment je dois procéder ?
Merci _________________ Monde de merde
Last edited by George Abitbol on Wed Apr 04, 2007 9:56 am; edited 1 time in total |
|
Back to top |
|
|
kwenspc Advocate
Joined: 21 Sep 2003 Posts: 4954
|
Posted: Wed Apr 04, 2007 9:34 am Post subject: |
|
|
initialise la variable total à l'extèrieur de ta boucle total=0 et utilises ensuite let genre: let total = $(($total + $size))
[edit] ah oui je précise: tel que ton code est fait de toute manière ça fonctionnerait pas (je crois) car total est "instancié" ici à chaque tour de boucle.
C'est comme si en C total était cree tel que int total; dans la boucle while. Mais je suis pas sûr de moi à 100% vu que je suis loin d'avoir un tas d'atomes crochus avec le bash[/edit]
[edit] désolé je vais me coucher... (avais pas vu tu initialisais déjà total avant) houlààà [/edit] _________________ membre officieux du SAV Ati GEntoo
Last edited by kwenspc on Wed Apr 04, 2007 9:57 am; edited 1 time in total |
|
Back to top |
|
|
DidgeriDude Guru
Joined: 30 Jan 2005 Posts: 349
|
Posted: Wed Apr 04, 2007 9:39 am Post subject: |
|
|
Et pourquoi pas adapter ceci qui fonctionne en ligne de commande :
Code: | total=0 ; for i in $(cat fichier | cut -d' ' -f 5) ; do total=$(($total + $i)) ; done ; echo $total |
EDIT : Bon, j'ai été fainéant, j'adapte ton script :
Code: | #!/bin/bash
# count.sh
total=0
erreur () {
echo -e "usage : \n\t$0 file\n"
exit
}
[[ $# == 1 ]] || erreur
echo -e "Processing file ${1}\n"
for size in $(cut -d' ' -f 5 "$1")
do
total=$(($total + $size))
done
echo -e "Total : ${total}\n"
echo -e "-- Exit --"
exit 0 |
|
|
Back to top |
|
|
George Abitbol n00b
Joined: 02 Feb 2006 Posts: 55
|
Posted: Wed Apr 04, 2007 9:55 am Post subject: |
|
|
ah ba oui, j'avais fait mon for comme ça :
Code: |
# for line in `cat $1` ;
# do
# size=`echo $line | cut -d ' ' -f 5`
# total=$(( $total + $size ))
#done
|
mas effectivement, en mettant le cut avant ça fonctione bien.
Merci ! _________________ Monde de merde |
|
Back to top |
|
|
George Abitbol n00b
Joined: 02 Feb 2006 Posts: 55
|
Posted: Wed Apr 04, 2007 10:01 am Post subject: |
|
|
Oui mais en fait, si j'avais voulu faire le total de n champs il aurait fallu que je fasse n loops. Y'aurait pas un truc pour faire ça en 1 seule loop (en fait plus généralement, pouvoir faire des traitements ligne par ligne avec un for) ? _________________ Monde de merde |
|
Back to top |
|
|
DidgeriDude Guru
Joined: 30 Jan 2005 Posts: 349
|
Posted: Wed Apr 04, 2007 10:05 am Post subject: |
|
|
Je comprends pas trop ce que tu veux dire... Tu veux un for, mais qui ne traite pas toutes les lignes à la suite ?
Je pense à awk, en formatant la sortie de manière à ce que les champs soient tous sur la même ligne, et séparés pas des +. Puis effectuer cette opération d'un coup... |
|
Back to top |
|
|
George Abitbol n00b
Joined: 02 Feb 2006 Posts: 55
|
Posted: Wed Apr 04, 2007 10:12 am Post subject: |
|
|
ben si justement, je veux un for qui me traite une ligne dans chaque loop, et le problème, c'est qu'avec un for i in `cat toto`, si les lignes contiennent des espaces, les $i auront pour valeur les champs de toutes les lignes, et non pas les lignes elles-mêmes. _________________ Monde de merde |
|
Back to top |
|
|
DidgeriDude Guru
Joined: 30 Jan 2005 Posts: 349
|
Posted: Wed Apr 04, 2007 10:24 am Post subject: |
|
|
OK, j'étais à côté de la plaque...
J'ai eu ce problème une fois, et j'avoue que je n'ai pas réussi à le régler, donc je l'ai contourné à coup de sed ou awk !!
Sinon, ton script peut se faire en une seule ligne :
Code: | echo $(($(cut -d' ' -f 5 "$1" | tr "\n" "+")0)) | (Remplacement des sauts de ligne par des "+" puis évaluation de l'expression... (Un 0 après le dernier "+" ne change rien... et évite l'erreur de syntaxe, en espérant que chaque ligne possède bien un 5ème champ !!) |
|
Back to top |
|
|
_droop_ l33t
Joined: 30 May 2004 Posts: 957
|
Posted: Wed Apr 04, 2007 11:17 am Post subject: |
|
|
Salut,
Pourquoi, personne n'a proposé la solution awk ?
Code: | awk '{ sum += $5; } END { print sum; }' fichier |
Ca a l'air de correspondre à ce qu'il voulait faire... |
|
Back to top |
|
|
George Abitbol n00b
Joined: 02 Feb 2006 Posts: 55
|
Posted: Wed Apr 04, 2007 11:46 am Post subject: |
|
|
_droop_ wrote: |
Code: | awk '{ sum += $5; } END { print sum; }' fichier |
|
o_O
il faut vraiment que je lise le man de awk...
Edit : et si je veux récupérer sum pour un traitement ultérieur dans le script (en dehors de sum=`awk ...`) (j'ai pas encore procédé à la lecture sus-mentionnée...) ? _________________ Monde de merde |
|
Back to top |
|
|
kaworu Guru
Joined: 07 Dec 2005 Posts: 450
|
Posted: Thu Apr 05, 2007 8:42 am Post subject: |
|
|
Salut !
Je me permet de te rediriger vers le magnifique et sublime : Guide avancé d'écriture des scripts Bash qui parle exactement du problème de déclaration de variables dans un "pipe" et des substitutions de processus.
En gros un pipe crée un sous processus et donc toutes variables déclarée dans le sous processus ne sont pus accessibles dans le processus père. La solution est d'utiliser la redirection de processus :
Code: |
alex@gentoo ~ $ echo "foo" | while read; do f=$REPLY; done
alex@gentoo ~ $ echo $f
alex@gentoo ~ $ while read; do f=$REPLY; done < <(echo "foo")
alex@gentoo ~ $ echo $f
foo
alex@gentoo ~ $
|
Effectivement, la solution awk semble la plus direct et la plus lisible ! vive awk/sed _________________ Macbook
Core2Duo @ 2.0GHz - 1Go RAM - HD 80Go - Intel GMA 945
Gentoo GNU/Linux
~amd64 - 2.6.24-gentoo-r2 - Fluxbox || (KDE && Compiz-Fusion) |
|
Back to top |
|
|
|