[Shell] extraire une colonne

Résolu

Bonjour,

Je tente de récupérer dans une ligne la 56 ème colonne.

La ligne est la suivante :
 

0_1 1 1 1 SIN_CREIND_CREIND 20080415 020000 H/STD/SIN_CREIND_CREIND OUT5000E recto 0 000291.xml 3960 E 3960 P 23 23-CM GM H Facturation F oui non non non 0 "IdxListeGed" 1719700 part1 123456789.pdf,123456790.pdf non non part1 1719700 Maladie SIN CREIND CREIND OUT5000 DECOMPTE DECOMPTE 01823-CM$789$789#

Mon script est le suivant :
 

read line
echo "$line"
var2=`echo $line | cut -d" " -f2`

echo lecture var2:$var2 change:$change

if [ "$var2" != "$change" ]
then
{
change=$var2
var1=`echo $line | cut -d" " -f1`
var3=`echo $line | cut -d" " -f3`
var4=`echo $line | cut -d" " -f4`
var5=`echo $line | cut -d" " -f5`
var6=`echo $line | cut -d" " -f31`

....

Actuellement, pour récupérer la colonne 56 je fais un f31. Je suppose que c'est parce qu'il y a des espaces ou des vides entre les tabulation.

Merci de bien vouloir m'aider

10 réponses

Résumé de la discussion

La problématique porte sur l’extraction de la 56e colonne d’une ligne de texte où les séparateurs tabulation et espaces compliquent le comptage des champs, et sur la faisabilité sous Windows XP avec cut et awk. Plusieurs répondants suggèrent awk avec -F'\t' pour imprimer directement le 56e champ, ou d’enchaîner une boucle read ligne afin de traiter chaque entrée séparément et de filtrer les résultats. D’autres évoquent une approche en boucle while read line et extraction du 56 avec awk -F'\t', puis traitement ligne par ligne pour éviter d’agréger le champ sur tout le fichier.

Bobot (l’IA à votre service)
  1. Modérateur
    Salut,

    Et avec "awk" c'est pas mieux ?
    awk '{ print $56 }'
    3960
    ;-))
    8
    1. Si 3960 est le résultat, il correspont soit au contenu de la colone 15 ou 17.

      Et comment mettre le contenu dans la variable.
      0
    2. Modérateur
      @yaLINUXNULSalut,

      que comprends tu par colonne?
      c'est quoi le séparateur des colonnes?
      0
    3. Modérateur
      @yaLINUXNULQuel est le contenu exact de la colonne que tu essaies de récupérer ?
      Quel(s) est(sont) le(s) séparateur(s) de champs contenu(s) dans la phrase ?

      Pour récupérer la variable c'est comme pour le reste :
      var=$(awk '{ print $56 }' fichier)
      ;-))
      0
    4. @lami20jPardon, j'ai oublié de mettre que le séparateur de colonne ou de champs est le carcatère 'tabulation'
      0
    5. @jipicyDans mon cas, fichier est une ligne du fichier et c'est le contenu de la colonne 56 de la ligne en cours .

      read line ....
      0
  2. Je tente d'améliorer les infos.
    Lorsque je liste le fichier first_ligne1.txt,
    J'obient le résultat suivant :
    ([tabulation] remplace le caractère qui ne doit pas passer dans l'interface.
    Celà est-il plus 'parlant'
    -----
    0_1[tabulation]1[tabulation]1[tabulation]1[tabulation]SIN_CREIND_CREIND[tabulation]20080415[tabulation]020000[tabulation]H/STD/SIN_CREIND_CREIND[tabulation]OUT5000E[tabulation][tabulation]recto[tabulation]0[tabulation]000291.xml[tabulation][tabulation]3960[tabulation]E[tabulation]3960[tabulation]P[tabulation]23[tabulation]23-CM[tabulation][tabulation][tabulation]GM[tabulation]H[tabulation][tabulation][tabulation][tabulation]Facturation[tabulation]F[tabulation][tabulation]oui[tabulation][tabulation][tabulation][tabulation][tabulation]non[tabulation][tabulation][tabulation]non[tabulation][tabulation][tabulation]non[tabulation]0[tabulation][tabulation][tabulation][tabulation][tabulation][tabulation][tabulation][tabulation][tabulation][tabulation]"IdxListeGed"[tabulation]1719700[tabulation]part1[tabulation]123456789.pdf,123456790.pdf[tabulation]non[tabulation]non[tabulation]part1[tabulation]1719700[tabulation]Maladie[tabulation]SIN[tabulation]CREIND[tabulation]CREIND[tabulation]OUT5000[tabulation]DECOMPTE[tabulation]DECOMPTE[tabulation][tabulation]01823-CM$789$789#
    -----

    read line
    echo "$line"
    var2=`echo $line | cut -d" " -f2`

    echo lecture var2:$var2 change:$change

    if [ "$var2" != "$change" ]

    then
    {
    echo "$line" >/opt/editic/adf/test_hy/test_groupe_mutuel/sortie/firt_ligne$var2.txt
    ligne_index=`echo $line`
    change=$var2
    var1=`echo $line | cut -d" " -f1`
    var3=`echo $line | cut -d" " -f3`
    var4=`echo $line | cut -d" " -f4`
    var5=`echo $line | cut -d" " -f5`
    var6=`echo $line | cut -d" " -f31`
    0
    1. le délimiteur de ton cut n'est pas bon
      pour une tabulation le caractère est \t ---> echo $line | cut -d "\t" -fX
      0
      1. insulte de la part du shell

        +++ cut '-d\t' -f31
        cut: Le délimiteur doit être un caractère simple.
        Pour en savoir davantage, faites: « cut --help ».
        ------
        var6=`echo $line | cut -d"\t" -f31`
        0
      2. @yaLINUXNUL... | cut -d "\t" -f X

        fais attention ou tu mets tes guillemets
        0
      3. @snoutsJ'ai fait un copié coller avec les espaces et j'ai la même insulte.
        0
    2. Modérateur
      awk -F"\t" '{ print $56 }'
      ;-))
      0
      1. jipicy adore awk ^^
        0
      2. Modérateur
        @snoutsSalut,

        dans ce cas je ne pense pas qu'il y a plus simple ;-)
        en revanche je crois que jipicy adore sed ;-))
        0
      3. J'ai l'impression que cette commande fonctionne en concatnnant les informations de tous les champs de toutes les lignes de mon fichier et ne donne pas l'information sur la ligne courante ?

        ou alors il faut que je supprime des éléments ...
        en mettant le var72, tout plante

        ------

        y=0
        change=oui
        while [ $y -ne $n ]
        do
        y=$(( $y + 1 ))

        read line
        echo "$line"
        var2=`echo $line | cut -d" " -f2`

        echo lecture var2:$var2 change:$change

        if [ "$var2" != "$change" ]

        then
        {
        echo "$line" >/opt/editic/adf/test_hy/test_groupe_mutuel/sortie/firt_ligne$var2.txt
        ligne_index=`echo $line`
        change=$var2
        var1=`echo $line | cut -d" " -f1`
        var3=`echo $line | cut -d" " -f3`
        var4=`echo $line | cut -d" " -f4`
        var5=`echo $line | cut -d" " -f5`
        var6=`echo $line | cut -d" " -f31`
        var72=$(awk -F"\t" '{ print $56 }')

        echo $var1
        echo $var2
        echo $var3
        echo $var4
        echo $var5
        echo $var6
        #echo $var72
        # Analyse des pdf
        #

        while read linea
        do
        echo "fichier : $linea"
        var10=`echo $linea`
        var12=`echo $var10 | cut -d"." -f1`
        var13=`echo $var10 | cut -d"." -f2`

        # appel de la fonction alpha
        alpha
        # appel de la fonction beta
        beta
        #done < <(echo $var6 | tr ',' '\n' | sort -u)
        done < <(echo $var72 | tr ',' '\n' | sort -u)

        }

        fi

        ------
        0
    3. Modérateur
      J'en reviens toujours au fait de demander quelle est la valeur à récupérer ???

      Chez moi avec ta ligne (celle avec les "[tabulation]"), en changeant chaque "[tabulation]" par une véritable "tabulation" et cette commande, voilà ce que j'obtiens :
      $ echo "$var" | awk -F"\t" '{ print $56 }'
      CREIND
      C'est la bonne valeur ?
      0
      1. la bonne valeur est :

        123456789.pdf,123456790.pdf

        cordialement
        0
    4. Modérateur
      Y'avait quelques soucis avec tes "[tabulation]", certaines contenaient des tirets et n'étaient donc pas transformées en "\t", mais maintenant ça marche :
      $ echo "$var" | awk -F"\t" '{ print $56 }'
      123456789.pdf,123456790.pdf
      ;-))
      0
      1. Bonjour, lil y a des progès.
        Mon soucis est que cette commande contanène les informations de l'ensembles des champs 56 du fichier. Je souhaiterai récupérer les information à chaque lecture séquentielle de ligne afin de traiter les fichiers pdf contenu dans le champs 1 par 1.
        actuellement, si mon fichier fait trois lignes et que je réalise ta commande, je récupére tous les noms de fichier pdf du fichier complet et non les noms des fichiers pdf de la ligne.
        Il y a peut être un paramètre permettant de travailler uniquements sur $line
        Qu'en penses-tu ?
        -----

        read line
        echo "$line"

        var72=$(awk -F"\t" '{ print $56 }')
        echo ttttt$var72

        while read linea
        do
        echo "fichier : $linea"
        var10=`echo $linea`
        var12=`echo $var10 | cut -d"." -f1`
        var13=`echo $var10 | cut -d"." -f2`
        done < <(echo $varvar72 | tr ',' '\n' | sort -u)

        }

        fi

        #done
        done < $1.tmp
        0
    5. Modérateur
      Ben il suffit de faire une boucle sur le fichier et de traiter chaque ligne à chaque itération de la boucle :
      while read line
      do
      var=$(awk -F"\t" '{ print $56 }' <<< "$line")
      ...
      ...
      ...
      done < fichier
      ;-))
      0
      1. dans mes variable en retour je me retruve avec des caractères que je n'attends pas :

        en passant la ligne de comm&nde :

        var72=$(awk -F"\t" '{ print $56 }' <<< "$line")
        ---

        résultat pour la ligne 1 : var72=$'123456789.pdf\r'
        résultat pour la ligne 2 : var72=$'123456791.pdf,123456790.pdf\r'

        ---
        0
    6. Modérateur
      Salut,

      que peux tu dire de la provenance de ton fichier?
      il ne viens pas depuis WIndows par hasard?
      0
      1. il peut venir de windows ou UNIX.

        J'ai vérifié sous vi, il n'y a pas de ^M en fin des lignes.

        C'est celà que tu attendais comme réponse ?
        0
    7. Modérateur
      Bon, pour ne pas tourner en rond et chose qu'on aurait du te demander d'entrée, donnes-nous ton fichier de référence (sur cjoint) et dis-nous exactement ce que tu veux faire avec des exemples :
      - Je veux extraire le champ 56 de chaque ligne (exemple valeur )
      - Le récupérer dans une variable myvar=
      - Ensuite blablabla
      - Blablabla
      ...
      0
      1. 0_1 1 1 ....
        1_1 1 2....
        2_1 2 1....

        Pour chaque champ 2 ayant la même valeur

        Ecrrire un fichier contennant la première ligne du champ 2 dans un fichier xx'numerochamps2'.txt
        Extraire la liste des pdf contenue dans le champ 56 (1 à n fichiers)
        Mettre dans une variable la dernière valeur du champ 3
        pour chaque fichier de la liste
        lancer une commande unix avec comme paramètre $1 = nom fichier pdf $2 = valeur du champ 3

        -----
        xxx.sh $1=123456791.pdf $2=2
        xxx.sh $1=123456790.pdf $2=2
        xxx.sh $1=123456789.pdf $2=1

        ------

        J'ai mis le fichier, j'espère que c'est ok. http://cjoint.com/data/ezlsIOdjOK.htm

        est ce clair ou faut il d'autres informations ?

        Cordialement
        0
    8. Modérateur
      Tiens essaie ça :
      [tmpfs]$ cat foo.sh
      #! /bin/bash
      
      change=0
      
      while read line
      do
      champ2=$(echo "${line}" |awk -F"\t" '{ print $2 }')
      if [ "${champ2}" != "${change}" ]
              then
                      liste=$(echo "${line}" | awk -F"\t" '{ print $56 }')
                      champ3=$(echo "${line}" | awk -F"\t" '{ print $3 }')
                      echo "${line}" > xx${champ2}.txt
                      change=${champ2}
                      grep ',' <<<${liste} >/dev/null
                      retval=$?
                      if [ "${retval}" = 0 ]
                              then continue
                      fi
              else
                      champ3=$(echo "${line}" | awk -F"\t" '{ print $3 }')
                      change=${champ2}
      fi
      
      for file in ${liste/,/ }
      do
      echo "commande.sh ${file} ${champ3}"
      done
      done < 000291.tmp
      
      [tmpfs]$ ./foo.sh
      commande.sh 123456791.pdf 2
      commande.sh 123456790.pdf 2
      commande.sh 123456789.pdf 1
      
      [tmpfs]$ ls
      000291.tmp  foo.sh*  xx1.txt  xx2.txt
      [tmpfs]$ 
      Si c'est bien ce que tu veux, change le 'echo "commande.sh ${file} ${champ3}"' par la commande appropriée ;-))
      0