Bash: Cách lấy một số dòng từ một tệp và lưu đầu ra vào một tệp khác [đã đóng]

Jan 17 2021

Tôi có một tệp nhật ký như thế này

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

Cách tạo giống như nhật ký được phân tích cú pháp mới để đầu ra của nhật ký tệp mới giống như sau:

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

Giống như chỉ nhận được tiến trình cuối cùng [ 60% 60920/101076]cho đến khi kết thúc tệp, sử dụng có thể là grep, sed hoặc bất cứ thứ gì. Cảm ơn bạn

Trả lời

dawg Jan 17 2021 at 22:29

Đây là một perl:

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

Hoặc một ống perl:

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

Đối với một awkbạn có thể làm:

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

Tất nhiên, bạn có thể biết rằng nếu lỗi luôn là 3 dòng, đơn giản nhất là chỉ cần sử dụng tail:

$ tail -n 3 file

Tất cả bản in:

[ 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

awklà công cụ phù hợp cho loại việc này. Ở đây, chúng tôi kiểm tra xem trường thứ 2 có khớp với trường thứ 2 của dòng trước đó hay không và in ra nếu có. Sau đó lưu dòng trước đó và lặp lại. Luôn in dòng cuối cùng của đầu vào.

potong Jan 17 2021 at 18:07

Điều này có thể phù hợp với bạn (GNU sed):

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

Nếu một dòng bắt đầu, hãy [lưu trữ nó trong không gian lưu giữ (ghi đè lên bất kỳ thứ gì trước đó ở đó).

Ngược lại, nối dòng hiện tại vào khoảng trống.

Xóa tất cả các dòng trừ dòng cuối cùng.

Ở cuối tệp, hoán đổi sang không gian lưu giữ và in nội dung của tệp.

IdrissNeumann Jan 17 2021 at 18:15

Đôi khi bạn không gặp may nếu muốn thực hiện loại bộ lọc này mà không cần phải thay đổi thứ tự của các dòng. Và nếu những dòng này không được viết ở đầu của tập tin của bạn, hoặc ở cuối: tac, sortuniqsẽ không phải là công cụ thích hợp.

Đây là một giải pháp sử dụng 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)) ####

Phiên bản có thể đọc và giải thích:

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

Sự khác biệt với các giải pháp của William Pursel là khi tỷ lệ phần trăm của bạn đang tăng lên. Hãy xem sự khác biệt của hành vi trong trường hợp này:

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

Vì vậy, bạn có thể muốn chọn nếu bạn chỉ muốn giữ dòng tiến trình cuối cùng ngay cả khi tỷ lệ phần trăm không giống nhau hoặc nếu bạn chỉ muốn lọc các dòng có cùng tỷ lệ phần trăm nhiều lần.

Enlico Jan 17 2021 at 18:47

Nếu nó được đảm bảo rằng dòng đầu tiên bạn muốn xóa là dòng cuối cùng bắt đầu [, thì bạn có thể làm điều này, về cơ bản thay thế mọi thứ từ đầu tệp đến dòng cuối cùng [trước đó bằng dấu ngắt dòng bằng một [:

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

Giả sử ...dòng ở đầu đầu vào mẫu của bạn đại diện cho nhiều [...] ...dòng ở đầu hơn :

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

Nếu giả định đó là sai thì vui lòng chỉnh sửa câu hỏi của bạn để hiển thị một ví dụ tối thiểu, đầy đủ , có thể xác minh được - một ví dụ chỉ có các giá trị đại diện, không phải ...s.