Bash:ファイルからいくつかの行を取得して出力を別のファイルに保存する方法[クローズ]

Jan 17 2021

私はこのようなログファイルを持っています

$ 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)) ####

新しいファイルログの出力が次のようになるように、新しい解析済みログのように生成する方法:

$ 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)) ####

[ 60% 60920/101076]たとえば、grep、sedなどを使用して、ファイルの最後まで最後の進行状況を取得するだけです。ありがとうございました

回答

dawg Jan 17 2021 at 22:29

これがperlです:

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

またはperlパイプ:

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

以下のためにawkあなたが行うことができます。

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

もちろん、失敗が常に3行である場合、最も簡単なのは単に使用することtailです。

$ tail -n 3 file

すべての印刷:

[ 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

awkこの種のものに適したツールです。ここでは、2番目のフィールドが前の行の2番目のフィールドと一致するかどうかを確認し、一致する場合は印刷します。次に、前の行を保存して繰り返します。入力の最後の行を常に出力します。

potong Jan 17 2021 at 18:07

これはあなたのために働くかもしれません(GNU sed):

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

行が開始された場合は、[それを保留スペースに格納します(以前にそこにあったものを上書きします)。

それ以外の場合は、現在の行を保留スペースに追加します。

最後を除くすべての行を削除します。

ファイルの終わりで、保留スペースにスワップして、その内容を印刷します。

IdrissNeumann Jan 17 2021 at 18:15

行の順序を変更せずにこの種のフィルターを実行したい場合は、運が悪い場合があります。そして、それらの行がファイルの最初または最後に書かれていない場合:tacsortそしてuniq適切なツールではありません。

以下を使用した解決策は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)) ####

読みやすく説明されたバージョン:

# 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]
    }
  }
}

William Purselソリューションとの違いは、パーセンテージが増加している場合です。この場合の動作の違いを見てみましょう。

$ 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)) ####

したがって、パーセンテージが同じでなくても最後の進行行のみを保持する場合、または同じパーセンテージの行のみを複数回フィルタリングする場合のいずれかを選択することをお勧めします。

Enlico Jan 17 2021 at 18:47

出力したい最初の行が[、で始まる最後の行であることが保証されている場合は、これを行うことができます。これにより、ファイルの先頭から[改行が前にある最後までのすべてが1つに置き換えられます[

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

...サンプル入力の先頭の[...] ...行がより多くの先行行を表すと仮定します。

$ 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)) ####

その仮定が間違っている場合は、質問を編集して、最小限の完全で検証可能な例を示してください...。これは、sではなく代表的な値のみを含むものです。