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]
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
Đâ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 awk
bạ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
$ 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
là 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.
Đ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.
Đô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
, sort
và uniq
sẽ 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.
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
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.