Bash: Comment récupérer des lignes d'un fichier et enregistrer la sortie dans un autre fichier [fermé]
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
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 awk
vous 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
$ 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
awk
est 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.
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.
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
, sort
et uniq
ne 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.
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
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.