Bash: Comment récupérer des lignes d'un fichier et enregistrer la sortie dans un autre fichier [fermé]

Jan 17 2021

J'ai un fichier journal comme celui-ci

$ cat build.log
..........
[ 60% 60917/101076] AAPT2 compile ....
[ 60% 60918/101076] AAPT2 compile ....
[ 60% 60919/101076] AAPT2 compile ....
[ 60% 60920/101076] AAPT2 compile ....
ninja: build stopped: subcommand failed.
21:41:22 ninja failed with: exit status 1

#### failed to build some targets (17:26 (mm:ss)) ####

Comment générer comme un nouveau journal analysé pour que la sortie du nouveau journal de fichier ressemble à ceci:

$ cat parsed.log
[ 60% 60920/101076] AAPT2 compile ....
ninja: build stopped: subcommand failed.
21:41:22 ninja failed with: exit status 1

#### failed to build some targets (17:26 (mm:ss)) ####

Comme obtenir seulement la dernière progression [ 60% 60920/101076]jusqu'à la fin du fichier, en utilisant peut-être grep, sed ou autre. Merci

Réponses

dawg Jan 17 2021 at 22:29

Voici un perl:

$ perl -0777 -lne 'print $1 if /(^\[[^[]*\z)/m' file

Ou un tube perl:

$ perl -E 'say reverse <>' file | perl -lpE 'if (/^\[/){ say; last}' | perl -E 'say reverse <>'

Pour un awkvous pouvez faire:

$ awk 'BEGIN{RS="\\["}END{print "[" $0}' file

Bien sûr, vous savez peut-être que si l'échec est toujours de 3 lignes, le plus simple est simplement d'utiliser tail:

$ tail -n 3 file

Tout imprimer:

[ 60% 60920/101076] AAPT2 compile ....
ninja: build stopped: subcommand failed.
21:41:22 ninja failed with: exit status 1
WilliamPursell Jan 17 2021 at 17:57
$ cat build.log ........ [ 60% 60917/101076] AAPT2 compile .... [ 60% 60918/101076] AAPT2 compile .... [ 60% 60919/101076] AAPT2 compile .... [ 60% 60920/101076] AAPT2 compile .... ninja: build stopped: subcommand failed. 21:41:22 ninja failed with: exit status 1 $ awk '$2 != n[2]{print p} {p = $0; split(p,n,FS)} END{print p}' build.log
........
[ 60% 60920/101076] AAPT2 compile ....
ninja: build stopped: subcommand failed.
21:41:22 ninja failed with: exit status 1

awkest le bon outil pour ce genre de chose. Ici, nous vérifions si le 2ème champ correspond au 2ème champ de la ligne précédente et imprimons si c'est le cas. Ensuite, enregistrez la ligne précédente et répétez. Imprimez toujours la dernière ligne de l'entrée.

potong Jan 17 2021 at 18:07

Cela pourrait fonctionner pour vous (GNU sed):

sed '/^\[/h;//!H;$!d;x' file

Si une ligne commence, [stockez-la dans l'espace d'attente (en écrasant tout ce qui s'y trouvait auparavant).

Sinon, ajoutez la ligne actuelle à l'espace d'attente.

Supprimez toutes les lignes sauf la dernière.

À la fin du fichier, passez à l'espace d'attente et imprimez son contenu.

IdrissNeumann Jan 17 2021 at 18:15

Parfois, vous n'avez pas de chance si vous souhaitez effectuer ce type de filtre sans avoir à changer l'ordre des lignes. Et si ces lignes ne sont pas écrites au début de votre fichier, ou à la fin: tac, sortet uniqne seraient pas les bons outils.

Voici une solution utilisant awk:

$ awk 'function push(a,e) { a[length(a)+1] = e } BEGIN {split("", lines); to_replace="toreplace"; exists=0} {if ($0 ~ "^\\[ [0-9]+%"){ll=$0; if (exists <= 0) {exists++; push(lines,to_replace)}} else {push(lines, $0)}} END {for (e in lines){if (lines[e] == to_replace) {print ll} else {print lines[e]}}}' test.log 
..........
[ 60% 60920/101076] AAPT2 compile ....
ninja: build stopped: subcommand failed.
21:41:22 ninja failed with: exit status 1

#### failed to build some targets (17:26 (mm:ss)) ####

La version lisible et expliquée:

# a function to append an element to an array dynamically
function push(a,e) { 
  a[length(a)+1] = e 
} 

BEGIN {
  split("", lines); # initializing an array
  to_replace="toreplace"; # you can change the replace key if you want
  exists=0
} 

{
  if ($0 ~ "^\\[ [0-9]+%"){ # matching all percentages/progression lines, regardless of their values ll=$0; 
    if (exists <= 0) {
      exists++; 
      push(lines, to_replace)
    }
  } else {
    push(lines, $0)
  }
}

END {
  for (e in lines) {
    if (lines[e] == to_replace) {
      print ll
    } else {
      print lines[e]
    }
  }
}

La différence avec les solutions William Pursel est lorsque vos pourcentages augmentent. Voyons la différence de comportement dans ce cas:

$ cat test.log 
..........
[ 60% 60917/101076] AAPT2 compile ....
[ 60% 60918/101076] AAPT2 compile ....
[ 60% 60919/101076] AAPT2 compile ....
[ 61% 60920/101076] AAPT2 compile ....
ninja: build stopped: subcommand failed.
21:41:22 ninja failed with: exit status 1

#### failed to build some targets (17:26 (mm:ss)) ####
$ awk 'function push(a,e) { a[length(a)+1] = e } BEGIN {split("", lines); to_replace="toreplace"; exists=0} {if ($0 ~ "^\\[ [0-9]+%"){ll=$0; if (exists <= 0) {exists++; push(lines,to_replace)}} else {push(lines, $0)}} END {for (e in lines){if (lines[e] == to_replace) {print ll} else {print lines[e]}}}' test.log 
..........
[ 61% 60920/101076] AAPT2 compile ....
ninja: build stopped: subcommand failed.
21:41:22 ninja failed with: exit status 1

#### failed to build some targets (17:26 (mm:ss)) ####
$ awk '$2 != n[2]{print p} {p = $0; split(p,n,FS)} END{print p}' test.log 
..........
[ 60% 60919/101076] AAPT2 compile ....
[ 61% 60920/101076] AAPT2 compile ....
ninja: build stopped: subcommand failed.
21:41:22 ninja failed with: exit status 1

#### failed to build some targets (17:26 (mm:ss)) ####

Vous pouvez donc choisir si vous ne souhaitez conserver que la dernière ligne de progression même si le pourcentage n'est pas le même ou si vous souhaitez uniquement filtrer les lignes qui ont le même pourcentage plusieurs fois.

Enlico Jan 17 2021 at 18:47

S'il est garanti que la première ligne que vous voulez sortir est la dernière ligne commençant par [, alors vous pouvez le faire, ce qui remplace essentiellement tout du début du fichier à la dernière [précédée d'un saut de ligne par un seul [:

sed -z 's/.*\n\[/[/' file
EdMorton Jan 17 2021 at 22:50

En supposant que la ...ligne au début de votre exemple d'entrée représente plus de [...] ...lignes principales :

$ awk '/^\[/{p=$0 ORS; next} {print p $0; p=""}' build.log
[ 60% 60920/101076] AAPT2 compile ....
ninja: build stopped: subcommand failed.
21:41:22 ninja failed with: exit status 1

#### failed to build some targets (17:26 (mm:ss)) ####

Si cette hypothèse est erronée, veuillez modifier votre question pour afficher un exemple minimal, complet et vérifiable - un exemple avec uniquement des valeurs représentatives, pas ...s.