Parcours de fichier (avec blancs) et ajout de caracteres
15 réponses
ozzii
Bonjour,
J'ai ceci sur sun (solaris):
#! /usr/bin/ksh
IFS=3D""
while read ligne
do
cc=3D`echo "$ligne"|cut -c120-120`
case $cc in
1) nli=3D"1"$ligne;;
*) nli=3D" "$ligne;;
esac
echo "${nli}"
done <$1
exit
Ce que je voudrais, c'est ajouter le chiffre 1 en d=E9but de ligne quand
je trouve 1 en position 120 et sinon rajouter un blanc. Tout ceci est
OK, mais cela prend un temps fou. Pour un fichier mis=E9reux de 3M, il
me met + de 10min.
Sinon, la moiti=E9 de mon probl=E8me c'est de faire un sed pour rajouter
un blanc en d=E9but de chaque ligne (et cela prend 1 sec). Mais il faut
quand m=EAme que je reparcours mon fichier pour faire la recherche du 1
en position 120.
Est-ce que quelqu'un =E0 une solution pour acc=E9l=E9rer le processus ?
L'instruction read lit octet par octet sur stdin, résultat, ça rrrrrrrrrraaaaaaaaaaaaaaaaaaaaaaaaammmmmmmmmmmmmmmmmeeeeeeee, comme le PO l'a constaté.
C'est le moindre des problemes (et certains shells comme bash et ksh le contourne quand l'input est seekable comme pour les fichiers reguliers).
C'est plus une question de facon de programmer. Un shell est un outil pour lancer des commandes. Programmer en shell veut dire utiliser tous ces outils qui ont une fonction precise pour qu'ils travaillent ensemble a accomplir une tache. Ce sont ces outils font le boulot, le shell, c'est juste la glue.
Dans une boucle while read, on va faire appel des milliers de fois a des outils qui ne vont meme pas travailler cooperativement. Le shell ne fait pas le boulot, il prend l'annuaire trouve le numero d'un plombier, lui demande de faire un boulot. Trouve le numero d'un charpentier et d'un couvreur et leur demande de s'arranger ensemble pour faire un toit.
Faire une boucle while read, c'est appeler un lecteur professionel, lui demander de lire la premiere ligne d'un manuel de plomberie, appeler un plombier, lui dire de devisser un ecrou, rappeler un autre lecteur pour la deuxieme ligne, appeler un autre plombier...
Sans parler de tous les autres problemes:
- La commande pour lire une ligne, ce n'est pas read mais IFS= read -r. Sans le IFS=, les blanks en debut et fin sont supprimés (et encore, ca depend des shells et de si il y a un "" avant le blank en fin de ligne). Sans -r, les backslashs sont interpretés comme des escapers de saut de ligne et de separateurs (et supprimés)
- Manipuler des variables en shell est delicat. La plutpart des gens ignorent qu'il faut les quoter (comme l'OP).
- dans: while IFS= read -r line; do cmd1; cmd2... done < fichier cmd1... ont perdu leur stdin original, vaudrait mieux faire:
while IFS= read -r line <&3; do { cmd1; cmd2 } 3<&- done 3< fichier
- sans parler de l'utilisation d'echo (qui est une commande a bannir) et des problemes habituels.
-- Stéphane
2007-01-12, 13:17(+00), Luc Habert:
Christophe Leitienne :
Eviter les boucles "while read" en shell!
Peut-on savoir pourquoi ?
L'instruction read lit octet par octet sur stdin, résultat, ça
rrrrrrrrrraaaaaaaaaaaaaaaaaaaaaaaaammmmmmmmmmmmmmmmmeeeeeeee, comme le PO
l'a constaté.
C'est le moindre des problemes (et certains shells comme bash et
ksh le contourne quand l'input est seekable comme pour les
fichiers reguliers).
C'est plus une question de facon de programmer. Un shell est un
outil pour lancer des commandes. Programmer en shell veut dire
utiliser tous ces outils qui ont une fonction precise pour
qu'ils travaillent ensemble a accomplir une tache. Ce sont ces
outils font le boulot, le shell, c'est juste la glue.
Dans une boucle while read, on va faire appel des milliers de
fois a des outils qui ne vont meme pas travailler
cooperativement. Le shell ne fait pas le boulot, il prend
l'annuaire trouve le numero d'un plombier, lui demande de faire
un boulot. Trouve le numero d'un charpentier et d'un couvreur et
leur demande de s'arranger ensemble pour faire un toit.
Faire une boucle while read, c'est appeler un lecteur
professionel, lui demander de lire la premiere ligne d'un manuel
de plomberie, appeler un plombier, lui dire de devisser un
ecrou, rappeler un autre lecteur pour la deuxieme ligne, appeler
un autre plombier...
Sans parler de tous les autres problemes:
- La commande pour lire une ligne, ce n'est pas read mais
IFS= read -r. Sans le IFS=, les blanks en debut et fin sont
supprimés (et encore, ca depend des shells et de si il y a un
"" avant le blank en fin de ligne). Sans -r, les backslashs
sont interpretés comme des escapers de saut de ligne et de
separateurs (et supprimés)
- Manipuler des variables en shell est delicat. La plutpart des
gens ignorent qu'il faut les quoter (comme l'OP).
- dans:
while IFS= read -r line; do
cmd1; cmd2...
done < fichier
cmd1... ont perdu leur stdin original, vaudrait mieux faire:
while IFS= read -r line <&3; do
{
cmd1; cmd2
} 3<&-
done 3< fichier
- sans parler de l'utilisation d'echo (qui est une commande a
bannir) et des problemes habituels.
L'instruction read lit octet par octet sur stdin, résultat, ça rrrrrrrrrraaaaaaaaaaaaaaaaaaaaaaaaammmmmmmmmmmmmmmmmeeeeeeee, comme le PO l'a constaté.
C'est le moindre des problemes (et certains shells comme bash et ksh le contourne quand l'input est seekable comme pour les fichiers reguliers).
C'est plus une question de facon de programmer. Un shell est un outil pour lancer des commandes. Programmer en shell veut dire utiliser tous ces outils qui ont une fonction precise pour qu'ils travaillent ensemble a accomplir une tache. Ce sont ces outils font le boulot, le shell, c'est juste la glue.
Dans une boucle while read, on va faire appel des milliers de fois a des outils qui ne vont meme pas travailler cooperativement. Le shell ne fait pas le boulot, il prend l'annuaire trouve le numero d'un plombier, lui demande de faire un boulot. Trouve le numero d'un charpentier et d'un couvreur et leur demande de s'arranger ensemble pour faire un toit.
Faire une boucle while read, c'est appeler un lecteur professionel, lui demander de lire la premiere ligne d'un manuel de plomberie, appeler un plombier, lui dire de devisser un ecrou, rappeler un autre lecteur pour la deuxieme ligne, appeler un autre plombier...
Sans parler de tous les autres problemes:
- La commande pour lire une ligne, ce n'est pas read mais IFS= read -r. Sans le IFS=, les blanks en debut et fin sont supprimés (et encore, ca depend des shells et de si il y a un "" avant le blank en fin de ligne). Sans -r, les backslashs sont interpretés comme des escapers de saut de ligne et de separateurs (et supprimés)
- Manipuler des variables en shell est delicat. La plutpart des gens ignorent qu'il faut les quoter (comme l'OP).
- dans: while IFS= read -r line; do cmd1; cmd2... done < fichier cmd1... ont perdu leur stdin original, vaudrait mieux faire:
while IFS= read -r line <&3; do { cmd1; cmd2 } 3<&- done 3< fichier
- sans parler de l'utilisation d'echo (qui est une commande a bannir) et des problemes habituels.
-- Stéphane
Stephane Chazelas
2007-01-12, 01:37(-08), ozzii:
Bonjour,
J'ai ceci sur sun (solaris):
#! /usr/bin/ksh IFS="" while read ligne do cc=`echo "$ligne"|cut -c120-120` case $cc in 1) nli="1"$ligne;; *) nli=" "$ligne;; esac echo "${nli}" done <$1 exit [...]
Sinon, avec certaines versions de ksh, on peut faire
#! /usr/bin/ksh - while IFS= read -r line; do case $line in ({119}(?)1*) line=1$line;; (*) line=" $line";; esac print -r -- "$line" done < "${1?}"
Mais encore une fois, c'est *mal*.
-- Stéphane
2007-01-12, 01:37(-08), ozzii:
Bonjour,
J'ai ceci sur sun (solaris):
#! /usr/bin/ksh
IFS=""
while read ligne
do
cc=`echo "$ligne"|cut -c120-120`
case $cc in
1) nli="1"$ligne;;
*) nli=" "$ligne;;
esac
echo "${nli}"
done <$1
exit
[...]
Sinon, avec certaines versions de ksh, on peut faire
#! /usr/bin/ksh -
while IFS= read -r line; do
case $line in
({119}(?)1*)
line=1$line;;
(*)
line=" $line";;
esac
print -r -- "$line"
done < "${1?}"
#! /usr/bin/ksh IFS="" while read ligne do cc=`echo "$ligne"|cut -c120-120` case $cc in 1) nli="1"$ligne;; *) nli=" "$ligne;; esac echo "${nli}" done <$1 exit [...]
Sinon, avec certaines versions de ksh, on peut faire
#! /usr/bin/ksh - while IFS= read -r line; do case $line in ({119}(?)1*) line=1$line;; (*) line=" $line";; esac print -r -- "$line" done < "${1?}"
Mais encore une fois, c'est *mal*.
-- Stéphane
Ozzii
Stephane Chazelas avait prétendu :
2007-01-12, 01:37(-08), ozzii: Sinon, avec certaines versions de ksh, on peut faire
#! /usr/bin/ksh - while IFS= read -r line; do case $line in ({119}(?)1*) line=1$line;; (*) line=" $line";; esac print -r -- "$line" done < "${1?}"
Mais encore une fois, c'est *mal*.
Merci pour cette info, mais j'ai utiliser le awk, et cela le fait tres bien. A partir de maintenant, je vais essayer de n'utiliser que cela pour les parcours des fichiers.
Stephane Chazelas avait prétendu :
2007-01-12, 01:37(-08), ozzii:
Sinon, avec certaines versions de ksh, on peut faire
#! /usr/bin/ksh -
while IFS= read -r line; do
case $line in
({119}(?)1*)
line=1$line;;
(*)
line=" $line";;
esac
print -r -- "$line"
done < "${1?}"
Mais encore une fois, c'est *mal*.
Merci pour cette info, mais j'ai utiliser le awk, et cela le fait tres
bien. A partir de maintenant, je vais essayer de n'utiliser que cela
pour les parcours des fichiers.
2007-01-12, 01:37(-08), ozzii: Sinon, avec certaines versions de ksh, on peut faire
#! /usr/bin/ksh - while IFS= read -r line; do case $line in ({119}(?)1*) line=1$line;; (*) line=" $line";; esac print -r -- "$line" done < "${1?}"
Mais encore une fois, c'est *mal*.
Merci pour cette info, mais j'ai utiliser le awk, et cela le fait tres bien. A partir de maintenant, je vais essayer de n'utiliser que cela pour les parcours des fichiers.
Ozzii
Stephane Chazelas a pensé très fort :
2007-01-12, 13:17(+00), Luc Habert: - sans parler de l'utilisation d'echo (qui est une commande a bannir)
Quoi utiliser a la place? Moi, dasn tous me scripts (quand j'en ai besoin), j'ai des echo.
Stephane Chazelas a pensé très fort :
2007-01-12, 13:17(+00), Luc Habert:
- sans parler de l'utilisation d'echo (qui est une commande a
bannir)
Quoi utiliser a la place? Moi, dasn tous me scripts (quand j'en ai
besoin), j'ai des echo.