полный новичок. С помощью awk можно напечатать следующее:
w171930 t1 Y z2545377 <--- print this line
w171930 t2 X z4495648
w171931 t1 Y z2555698 <--- print this line
w171931 t2 X z5505690
w171932 t1 Y z2554345 <--- print this line
w171932 t2 X z5507345
w171933 t1 Y z2214694
w171933 t2 Y z8022710
w171933 t3 Y z2143462
w171933 t4 Y z6217556
w171933 t5 Y z9608343
w171933 t6 Y z9984446
w171933 t7 Y z2985572
w171933 t8 Y z6334512 <--- print this line
w171933 t9 X z6503375
w171943 t1 Y z2441603 <--- NO print this line
w171943 t2 X z4644534
w171943 t3 Y z2164440
w171944 t1 Y z2165532
Найдите $3 == "X" и напечатайте предыдущую строку, если в следующей строке есть $2 == "t1"
Цель
w171930 t1 Y z2545377
w171931 t1 Y z2555698
w171932 t1 Y z2554345
w171933 t8 Y z6334512
Мне удалось напечатать только предыдущую строку, но я не знаю, как выполнить полное условие
awk '$3 == "Y" { Y=$0; next; } { if ($3 =="X") print Y;}'
извиняюсь, если не правильно выражаюсь
awk '$2=="t1"{ if(prev2!="" && prev!="") print prev2 }
{ prev=($3=="X"?prev2:""); prev2=$0 }' input
$2=="t1"
только для строк, где второй элемент = "t1". Когда prev
и prev2
имеют значение, мы должны вывести это значение.prev
будет содержать значение prev2
, когда третий элемент равен "X"prev2
будет иметь значение строки, которую нужно вернуть.Другое решение с awk
:
$ awk '$2=="t1" && third=="X"{print line2}
{line2=line1; line1=$0; third=$3}' ip.txt
w171930 t1 Y z2545377
w171931 t1 Y z2555698
w171932 t1 Y z2554345
w171933 t8 Y z6334512
line1
будет иметь предыдущую строку, а line2
будет иметь предыдущую, но одну строкуthird
сохраняет содержимое 3-го поля предыдущей строкиt1
, проверьте, является ли 3-е поле предыдущей строки X
, и если да, напечатайте предыдущую, но одну строкуЧто касается вашего требования:
Search on $3 == "X" and print the previous line if the next line has a $2 == "t1"
Как и в жизни, в программном обеспечении гораздо проще делать вещи, основываясь на том, что ПРОИЗОШЛО, а не на том, что произойдет, поэтому не пишите требования, основываясь на том, что будет СЛЕДУЮЩЕЕ, пишите их на основе того, что было в ПРЕДЫДУЩИХ вещах, и вы сами. Нам будет намного легче концептуализировать и написать код для их реализации. В этом случае ваше требование должно быть записано как:
If $2 == "t1" in the current line and $3 == "X" in the previous line then print the line before that.
что приводит к очевидной реализации:
$ awk '($2=="t1") && (p3=="X") {print pp0} {pp0=p0; p0=$0; p3=$3}' file
w171930 t1 Y z2545377 <--- print this line
w171931 t1 Y z2555698 <--- print this line
w171932 t1 Y z2554345 <--- print this line
w171933 t8 Y z6334512 <--- print this line
Вы можете сделать это с помощью регулярное выражение, если хотите, что можно сделать в Perl:
perl -0777 -nE 'while (/^.*\R(?=(?:\S+\s){2}X\s\S+\R\S+\st1)/gm) {print $&}' file
Или, немного изменив регулярное выражение, вы можете использовать GNU Grep:
grep -ozP '.*\R(?=(?:\S+\s){2}X\s\S+\R\S+\st1)' file | tr -d '\000'
Или ruby
:
ruby -e 'puts $<.read.scan(/(.*\R)(?=(?:\S+\s){2}X\s\S+\R\S+\st1)/)' file
Любой из них (с вашим примером ввода) печатает:
w171930 t1 Y z2545377 <--- print this line
w171931 t1 Y z2555698 <--- print this line
w171932 t1 Y z2554345 <--- print this line
w171933 t8 Y z6334512 <--- print this line
tr -d '\000'
удаляет окончания строк NUL
, вставленные GNU grep.
немного многословно, но он выполняет свою работу:
<<<"${aa}" mawk '
BEGIN {
_+=++_
} {
do {____=$((__=$_)<"")
} while($(_+getline)=="Y")
if(___<("X"==$++_)) {
printf("%s%.*s",____,\
(___=__!="t1")<_,ORS) }; -—_}'
w171930 t1 Y z2545377
w171931 t1 Y z2555698
w171932 t1 Y z2554345
w171933 t8 Y z6334512
ваше решение предлагает мне следующее:
awk '$2 == "t1" {if (key == "X") print a_copy} {a_copy=prev;prev=$0;key=$3}' file
где мы печатаем копию предыдущей строки.