[gull] Truc et astuces: Jouons avec `sed`

felix felix at f-hauri.ch
Wed Feb 5 19:13:01 CET 2014


Re,

On Wed, Feb 05, 2014 at 02:18:26PM +0100, ZaZo0o wrote:
> 
> http://sed.sourceforge.net/sed1line_fr.html
> On y trouve un peu de tout...

Oui, mais c'est plein de solutions ``overkill'' du type: remplacer

 $ cat -n fichier 
par
 $ sed = fichier | sed 'N; s/^/     /; s/ *\(.\{6,\}\)\n/\1  /'

Joli, mais inutile et contre-productif (cat `cat` fait le même travail
plus vite et sans impliquer un fork), comme remplacer `tac` par

 $ sed '1!G;h;$!d'

Marrant, mais combien de fois t'es tu retrouvé en situation d'avoir besoin
de ce genre de fonctionnalité (sans disposer de `tac`?)

Les exemples que je propose sont fonctionnels et répondent à des question
qui m'ont été posées...

Pour finir d'enfoncer le clou à propos de ces ``vielles pages d'astuces'',
c'est plein de ``mauvaises habitudes'' comme:

 `` cat nomdefichier | sed '10q'             # utilise entrée pipeline
    sed '10q' nomdefichier                   # même chose, en moins du cat inutile
    sed '10q' nomdefichier > nouveaufichier  # re dirige la sortie vers le disque
 ''

où la première ligne serait mieux écrite:
    sed '10q' < nomdefichier    # qui en fait, n'est pas la même chose que
    sed '10q' nomdefichier

En effet, il est intéressant de noter que `sed` peut se comporter soit

 - comme un filtre, agissant sur l'entrée standard
 - comme un moteur d'édition agissant sur des fichiers.

en particulier, avec l'option `-i`, sed effectuera des modifications
sur les fichiers ``in place'', ( par conséquent, l'option `-i` devient
ineffective si sed agit sur l'entrée standard... )

Mais la syntaxe ``cat file |'' doit (à mon avis) être bannie des tutoriels
à présent.

Enfin, une autre question m'a été posée:

- Comment imprimer un morceau de fichier, délimité par des chaines, mais
  seulement si le morceau contient une chaine (ou regexp) sur l'une
  de ses lignes...

  (Nota les variables sont modifiées par bash afin de pouvoir contenir
   des slashes, p. ex: end="</div>" )

  sed -ne "
      /${start//\//\\/}/,/${end//\//\\/}/ {
        H;
	/${start//\//\\/}/    { x;
                   };
        /${end//\//\\/}/  {
                     s/^.*$//;
                     x;
                     /${cndstr//\//\\/}/p;
                     d;
                   };
      }
  "

  Cette routine à été mise au point en remplaçant la 1ère ligne par:

  sed -ne < <(seq 1 9 ;seq 1 9) "
    ..."

  et en jouant avec: 

  start=3 end=8 cndstr=2
  start=3 end=8 cndstr=3
  start=3 end=8 cndstr=5
  start=3 end=8 cndstr=8
  start=3 end=8 cndstr=9
  start=3 end=2 cndstr=3
  start=3 end=2 cndstr=3

  ...puis testée avec:

  start='<div' end='</div>' cndstr='class="banner'
  nc f-hauri.ch 80 <<<$'GET /root/index.html HTTP/1.0\r\nHost: f-hauri.ch\r\n\r' |
    sed '1,/^\r\?$/d;s/>/>\n/g' |
    sed -ne " 
      /${start//\//\\/}/,/${end//\//\\/}/ {
        H;
        /${start//\//\\/}/    { x;
                   };
        /${end//\//\\/}/  {
                     s/^.*$//;x; 
                     /${cndstr//\//\\/}/p;
                     d;
                   };
      }
  "

( Utiliser `sed` à la place de wget est aussi ``overkill'', mais sed me permet
  d'ajouter un saut de ligne à la volé après *chaque* tag )

Voilà, pour les plus ardus, petit challenge: `indexer une sortie de `ls'':

 $ /bin/ls -1 /bin | sed "..."
 b
   bash
   bunzip2
   busybox
   bzcat
 ...
 c
   cat
   chacl
 ...
 z
  zcat

ou encore, avec l'argument `-l`:

  $ /bin/ls -l /bin | sed "..."
  b
    -rwxr-xr-x 1 root root 975488 déc 30  2012 bash
    -rwxr-xr-x 3 root root  31184 jui 29  2012 bunzip2
    -rwxr-xr-x 1 root root 697656 sep 20  2012 busybox
  ...
    -rwxr-xr-x 1 root root  18760 fév 16  2012 hostname
  i
    -rwxr-xr-x 1 root root 249976 mar  2  2013 ip
  k
    -rwxr-xr-x 1 root root  22952 mar 28  2013 kill
  ...

A vos claviers!

(Pour info, mon script fait 63 caractères avec `-1` et 129 caractères avec `-l`)

--
 Félix Hauri  -  <felix at f-hauri.ch>  -  http://www.f-hauri.ch


More information about the gull mailing list