बैश: एक फ़ाइल से कुछ लाइनें कैसे प्राप्त करें और आउटपुट को दूसरी फ़ाइल में सहेजें [बंद]
मेरे पास इस तरह की एक लॉग फाइल है
$ 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, या किसी भी चीज़ का उपयोग करके। धन्यवाद
जवाब
यहाँ एक प्रति है:
$ perl -0777 -lne 'print $1 if /(^\[[^[]*\z)/m' file
या एक पर्ल पाइप:
$ 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
$ 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
इस तरह की चीज़ के लिए सही उपकरण है। यहां, हम जांचते हैं कि क्या दूसरा फ़ील्ड पिछली पंक्ति के दूसरे फ़ील्ड से मेल खाता है और यदि ऐसा है तो प्रिंट करें। फिर पिछली पंक्ति को स्टोर करें और दोहराएं। हमेशा इनपुट की अंतिम लाइन प्रिंट करें।
यह आपके लिए काम कर सकता है (GNU sed):
sed '/^\[/h;//!H;$!d;x' file
यदि कोई लाइन [
इसे होल्ड स्पेस में संग्रहीत करना शुरू कर देती है (पहले से कुछ भी लिखती है)।
ओथेवाइज, वर्तमान लाइन को होल्ड स्पेस में जोड़ता है।
अंतिम को छोड़कर सभी लाइनें हटाएं।
फ़ाइल के अंत में, होल्ड स्पेस पर स्वैप करें और इसकी सामग्री प्रिंट करें।
यदि आप लाइनों के क्रम को बदलने के बिना इस तरह के फिल्टर का प्रदर्शन करना चाहते हैं तो आप कभी-कभी भाग्यशाली नहीं होते हैं। और उन पंक्तियों अपनी फ़ाइल की शुरुआत में लिखा है, तो नहीं कर रहे हैं, या अंत में: tac
, sort
और 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]
}
}
}
विलियम पर्सल समाधान के साथ अंतर तब है जब आपके प्रतिशत बढ़ रहे हैं। आइए इस मामले में व्यवहार का अंतर देखें:
$ 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)) ####
तो आप या तो यह चुन सकते हैं कि यदि आप केवल अंतिम प्रगति पंक्ति रखना चाहते हैं, भले ही प्रतिशत समान न हो या यदि आप केवल उन पंक्तियों को फ़िल्टर करना चाहते हैं जिनमें एक ही प्रतिशत कई बार है।
यदि यह गारंटी है कि पहली लाइन जिसे आप शुरू करना चाहते हैं [
, तो यह अंतिम पंक्ति है , जिसके बाद आप यह कर सकते हैं, जो अनिवार्य रूप से फाइल की शुरुआत से लेकर अंतिम [
लाइन लाइन द्वारा एकल के साथ पूर्ववर्ती सब कुछ बदल देता है [
:
sed -z 's/.*\n\[/[/' file
...
अपने नमूना इनपुट के प्रारंभ में रेखा मान लेना अधिक अग्रणी [...] ...
रेखाओं का प्रतिनिधित्व करता है :
$ 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)) ####
यदि वह धारणा गलत है, तो कृपया अपने प्रश्न को एक न्यूनतम, पूर्ण , सत्यापित उदाहरण दिखाने के लिए संपादित करें - केवल प्रतिनिधि मूल्यों के साथ, ...
एस नहीं ।