5 votes

AWK Fractionne le fichier toutes les n-ième lignes mais regroupe les ID ensemble

Supposons que j'aie le fichier suivant text.txt :

@something
@somethingelse
@anotherthing
1
2
2
3
3
3
4
4
4
5
5
6
7
7
8
9
9
9
10
11
11
11
14
15

Je veux diviser ce fichier en plusieurs fichiers à chaque 5ème ligne de données, mais si le numéro de la ligne suivante est identique, il doit toujours se retrouver dans le même fichier. L'en-tête doit figurer dans chaque fichier, mais il peut également être ignoré et réintroduit ultérieurement.
Cela signifie à peu près ceci :

text.txt.1
@something
@somethingelse
@anotherthing
1
2
2
3
3
3

text.txt.2
@something
@somethingelse
@anotherthing
4
4
4
5
5

text.txt.3
@something
@somethingelse
@anotherthing
6
7
7
8
9
9
9

text.txt.4
@something
@somethingelse
@anotherthing
10
11
11
11
14

text.txt.5
@something
@somethingelse
@anotherthing
15

J'ai donc pensé à quelque chose comme ça :

awk 'NR%5==1 && $1!=prev{i++;prev=$1}{print > FILENAME"."i}' test.txt

Les deux instructions fonctionnent seules mais pas ensemble est-ce possible en utilisant awk ?

5voto

POW Points 330

Bonne question.
Dans votre exemple, cela fonctionnerait :

awk 'BEGIN{i=1;}/\@/{header= header == ""? $0 : header "\n" $0; next}c>=5 && $1!=prev{i++;c=0;}{if(!c) print header>FILENAME"."i; print > FILENAME"."i;c++;prev=$1;}' test.txt

Vous devez retirer l'en-tête et définir un compteur ( c ci-dessus), NR est simplement le numéro de ligne actuel de l'entrée, il ne répondra pas à vos besoins lorsque les lignes réelles ne sont pas des fois 5.

Cassez-la et améliorez-la un tout petit peu :

awk 'BEGIN{i=1;}
  /\@/{header= header == ""? $0 : header ORS $0; next}
  c>=5 && $1!=prev{i++;c=0;}
  !c {print header>FILENAME"."i;}
  {print > FILENAME"."i;c++;prev=$1;}
  ' test.txt

Pour résoudre les problèmes potentiels mentionnés dans le commentaire :

awk 'BEGIN{i=1}
  /\@/{header= header == ""? $0 : header ORS $0; next}
  c>=5 && $1!=prev{i++;c=0}
  !c {close(f);f=(FILENAME"."i);print header>f}
  {print>f;c++;prev=$1}
  ' test.txt

ou chèque Réponse de Ed qui est plus précis et compatible avec différentes plates-formes/versions.

4voto

RavinderSingh13 Points 29608

Avec les échantillons que vous avez montrés, veuillez essayer ce qui suit awk programme. Écrit et testé en GNU awk .

awk '
BEGIN{
  outFile="test.txt"
  count=1
}
/@/{
  header=(header?header ORS:"")$0
  next
}
{
  arr[$0]=(arr[$0]?arr[$0] ORS:"")$0
}
END{
  PROCINFO["sorted_in"] = "@ind_num_asc"
  print header > (outFile count)
  for(i in arr){
    num=split(arr[i],arr2,"\n")
    print arr[i] > (outFile count)
    len+=num
    if(len>=5){ len=0 }
    if(len==0){
      close(outFile count)
      count++
      print header > (outFile count)
    }
  }
}
'  Input_file

4voto

Ed Morton Points 25374

Utiliser n'importe quel awk dans n'importe quel shell sur n'importe quelle machine Unix :

$ cat tst.awk
/^@/ {
    hdr = hdr $0 ORS
    next
}
( (++numLines) % 5 ) == 1 {
    if ( $0 == prev ) {
        --numLines
    }
    else {
        close(out)
        out = FILENAME "." (++numBlocks)
        printf "%s", hdr > out
        numLines = 1
    }
}
{
    print > out
    prev = $0
}

$ awk -f tst.awk text.txt

$ head text.txt.*
==> text.txt.1 <==
@something
@somethingelse
@anotherthing
1
2
2
3
3
3

==> text.txt.2 <==
@something
@somethingelse
@anotherthing
4
4
4
5
5

==> text.txt.3 <==
@something
@somethingelse
@anotherthing
6
7
7
8
9
9
9

==> text.txt.4 <==
@something
@somethingelse
@anotherthing
10
11
11
11
14

==> text.txt.5 <==
@something
@somethingelse
@anotherthing
15

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X