Forum Programmation.shell Extraction avec awk...

Posté par  (site web personnel) .
Étiquettes : aucune
0
17
nov.
2010
Bonjour à tous (toutes),

Je ne suis pas un grand spécialiste de la programmation du shell (/bin/bash) et je bute sur la résolution suivante:

je cherche à extraire d'une chaîne, l'ensemble de la chaîne sauf le premier champ et sans le séparateur. la chaine pouvant être constituée de 2 à n champs..

ex:

[code]
echo "un deux trois quatre" | awk '{ $1=""; print $0;}'
deux trois quatre
[/code]

le problème est que je ne veux pas récupérer le premier séparateur et que d'autre part la chaine peut être constituée de 2 à n champs (ex: "Un deux", "Un deux trois", "Un deux trois ..."

je voudrais éviter d'utiliser la fonction split est-ce possible ?
  • # cut ?

    Posté par  . Évalué à 7.

    echo "un deux trois quatre" | cut -d' ' -f2-
    deux trois quatre
    • [^] # Re: cut ?

      Posté par  (site web personnel) . Évalué à 2.

      Merci. Il me manquait l'astuce du - à la fin de la commande cut pour récupérer à partir du deuxième champ jusqu'à la fin de la ligne.

      Existe-t-il un (ou plusieurs) site(s) sympa sur le bash ?
    • [^] # pour le fun :

      Posté par  . Évalué à 4.

      expr "un deux trois quatre" : "[^ ]* \(.*\)"
      deux trois quatre

      ou

      echo "un deux trois quatre" |sed 's/[^ ]* //'

      ou

      echo "un deux trois quatre" | awk ' sub(/^[^ ]* /,"",$0)'
      • [^] # en pur shell

        Posté par  . Évalué à 4.

        CHAINE="un deux trois quatre"
        echo ${CHAINE#[^ ]* }
        deux trois quatre
        • [^] # grep

          Posté par  . Évalué à 3.

          Ouille plus difficile en grep, d'autant plus qu'il faut adapter 2 au nombre de colonnes :

          echo "un deux trois quatre" | grep -Eo "([^ ]* ){2}[a-z]*$"
          deux trois quatre
        • [^] # Re: en pur shell

          Posté par  . Évalué à 3.

          Il me semble que c'est de loin la meilleure solution (ou de moins celle que je préfère) :
          pas de programme extérieur & compacte

          Tous les contenus que j'écris ici sont sous licence CC0 (j'abandonne autant que possible mes droits d'auteur sur mes écrits)

          • [^] # Re: en pur shell

            Posté par  . Évalué à 3.

            Oui c'est mieux, pas de processus fils,

            fearan à même trouvé encore plus court :

            CHAINE="un deux trois quatre"
            echo ${CHAINE#* }
  • # Si tu veux vraiment utiliser AWK

    Posté par  . Évalué à 2.

    echo "un deux trois quatre" | awk '{$1=""; sub(" ", ""); print}'

    Mais bon, cut est vraiment plus adapté pour ça que AWK, qu'il faut limite réserver à des utilisations plus poussées.

    Merci.
    • [^] # Re: Si tu veux vraiment utiliser AWK

      Posté par  . Évalué à 2.

      J'ai mieux ...

      echo "un deux trois quatre" |awk '{sub($1 FS,"");print}'

      Si on remplace le séparateur de champ :

      echo "un;deux;trois;quatre" |awk -F\; '{sub($1 FS,"");print }'
    • [^] # Re: Si tu veux vraiment utiliser AWK

      Posté par  . Évalué à 3.

      C'est pas mal de savoir le faire en AWK, ça évite ensuite des aberrations dy style cat | grep .... | cut .... | awk ... | sed ...
  • # avec une boucle for ?

    Posté par  (site web personnel) . Évalué à 2.

    echo "un deux trois quatre" | awk '{ for (i = 2; i <= NF; i++)print $i}'
    • [^] # Re: avec une boucle for ?

      Posté par  . Évalué à 2.

      Oui, mais tu ne renvois un enregistrement par ligne.

      echo "un deux trois quatre" | awk '{ for (i = 2; i <= NF; i++)print $i}' | tr '\n' ' ' | sed "s/ $/\n/"

      Voici le genre de trucs que ça peut donner à la fin (et encore, c'est bien crade, :D).
      • [^] # Re: avec une boucle for ?

        Posté par  . Évalué à 1.

        echo "un deux trois quatre" | awk '{t=""; for (i = 2; i <= NF; i++){if(i==NF){t=t$i}else{t=t$i" "}}; print t}'

        Totalement en AWK, mais ça en devient totalement illisible, :).
        • [^] # Re: avec une boucle for ?

          Posté par  . Évalué à 2.

          Moins moche :

          echo "un deux trois quatre" |awk -F"[ \\t]+" ' {sub($1"("FS")","");print }'

          L'avantage de cette règle est que tu peux avoir des champs séparés d'une ou plusieurs tablulation ou espaces ....

          Amusant ce petit problème. Ca détend :)
  • # Après, on peut toujours s'amuser avec d'autres outils

    Posté par  . Évalué à 2.

    Ça donne des syntaxes intéressantes, comme avec sed :

    echo "un deux trois quatre" | sed 's/^.[^* ] //'

    Ça vire le premier champ, peut importe ce qu'il contient.

    Après, je suis persuadé que c'est facilement faisable dans d'autres langages, mais qui risquent de rendre le script de moins en moins maintenable, :D.
    • [^] # Re: Après, on peut toujours s'amuser avec d'autres outils

      Posté par  . Évalué à 1.

      En repartant sur cette forme davro-newbsienne-ircienne et en utilisant le meilleur langage du monde après le C et l'assembleur, j'ai nommé perl, on a ça :
      echo "un deux trois quatre"| perl -pe 's/^.[^* ] //;'
      • [^] # Re: Après, on peut toujours s'amuser avec d'autres outils

        Posté par  (site web personnel) . Évalué à 1.

        ha non désolé, c'est raté [l'a pas lu les consignes ;-) ]

        je ne veux pas récupérer le premier séparateur de champ (l'espace entre 'un' et 'deux' ) !!!

        Bon de toute façon je n'allais pas mettre un morceau de perl dans mon bash sinon il fallait tout faire en perl .... ;-)

        cut me va très bien et en plus (pour une fois) c'est élégant...
  • # avec un shift

    Posté par  (site web personnel) . Évalué à 8.

    avec le script suivant

    #!/bin/sh

    shift
    echo "$*"

    $ ./essai.sh un deux trois qautre
    deux trois qautre
    • [^] # Re: avec un shift

      Posté par  . Évalué à 2.

      à mon avis c'est de loin la solution la plus optimisée, mais surtout la plus simple de tous les posts de cette entrée de forum.

      C'est tout con mais il fallait y penser, sachant que l'IFS répond déjà à la problématique initiale.
  • # a moi

    Posté par  . Évalué à 5.

    2 solutions :)

    echo "a b c d"| ( read a b ; echo $b)
    b c d

    ou

    a="a b c d"
    echo ${a#* }
    b c d

    Il ne faut pas décorner les boeufs avant d'avoir semé le vent

  • # Une solution courte

    Posté par  . Évalué à 1.


    cat undeuxtrois| awk -F: ' { gsub($1FS$2,$2) ; print $0 }'

Suivre le flux des commentaires

Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.