Если строка под предыдущей строкой равна конкретному значению первого столбца, выведите две строки - PullRequest
3 голосов
/ 09 марта 2019

У меня есть переменный входной файл, который можно отформатировать, как показано ниже.

text1 valueA valueN valueB
text2 valueX
text1 valueC valueN valueD
text2 valueX
text1 valueE valueM valueF
text1 valueG valueM valueH
text1 valueI valueN valueJ
text2 valueX
text1 valueK valueO valueL
text1 valueP valueO valueQ
text1 valueR valueN valueS
text1 valueT valueM valueU

Я хочу напечатать text1 valueA valueN valueB, только если под предыдущей строкой существует text2 valueX.Например, вывод должен быть:

text1 valueA valueN valueB
text2 valueX
text1 valueC valueN valueD
text2 valueX
text1 valueI valueN valueJ
text2 valueX

Мне также нужно иметь возможность соответствовать части valueX.Допустим, valueX=a.b.c.d-e, мне нужно сопоставить a.b.

myvariable=a.b.
echo $myvariable
a.b.

Обновление : извинения за нечеткие входные данные ... Я предположил, что смог сопоставить частичный текст, но я былнеправильно.

Поэтому, если данные выглядят так:

text1 valueA valueN valueB
text2 a.b.c.d-e
text1 valueC valueN valueD
text2 a.b.c.d-e
text1 valueE valueM valueF
text1 valueG valueM valueH
text1 valueI valueN valueJ
text2 a.b.c.d-e
text1 valueK valueO valueL
text1 valueP valueO valueQ
text1 valueR valueN valueS
text1 valueT valueM valueU

Как бы вы соответствовали, например, a.b., если val=a.b.

echo $val
a.b.

Ответы [ 5 ]

2 голосов
/ 09 марта 2019

Вот один в awk:

$ awk '$0=="text2 valueX"{print p ORS $0}{p=$0}' file

Вывод:

text1 valueA valueN valueB
text2 valueX
text1 valueC valueN valueD
text2 valueX
text1 valueI valueN valueJ
text2 valueX

Объяснено:

$ awk '
$0=="text2 valueX" {  # if record is a match
    print p ORS $0    # print previous buffered record and current
}
{
    p=$0              # buffer record for next round
}' file

Обновлено обновление с обновлениемdata:

Поскольку . является метачленом регулярных выражений, его необходимо экранировать при вводе, чтобы избежать совпадения, например, с abbb:

$ awk -v s="a\\\.b\\\." '$0~s{print p ORS $0}{p=$0}' file

Вывести сейчас:

text1 valueA valueN valueB
text2 a.b.c.d-e
text1 valueC valueN valueD
text2 a.b.c.d-e
text1 valueI valueN valueJ
text2 a.b.c.d-e
1 голос
/ 09 марта 2019

A sed решение:

$ sed -n -e '/text2 valueX/{' -e 'H;x;p;}' -e 'h' file
text1 valueA valueN valueB
text2 valueX
text1 valueC valueN valueD
text2 valueX
text1 valueI valueN valueJ
text2 valueX

Измените регулярное выражение на /^text2 valueX$/, если вы хотите сопоставить всю строку.

Это равно GNU sed:

 sed -n '/text2 valueX/{H;x;p;};h' file

POSIX sed необходимо начать новую строку или новый блок -e после { открытой скобки или } закрывающей скобки.

H   Append the contents of pattern space to hold space, separate them by a newline character.
x   Exchange the contents of pattern space and hold space.
p   Print the contents of pattern space.
h   Overwrite the contents of hold space with pattern space.

/text2 valueX/ - это регулярное выражение, этосоответствует текущей строке (пробелу), если она соответствует, команде или блоку {} после того, как он будет выполнен.
Внутри блока добавьте строку для хранения пробела, в котором уже есть последняя строка.Затем замените пространство удержания на пространство образца, затем напечатайте.
И после блока вставьте текущую строку в пространство удержания, чтобы заменить прежнее содержимое.

Примечание: с этим решением вы не можете иметь несколько text2 valueX последовательных строки, в противном случае будут напечатаны дополнительные строки.Если что-то случится, пожалуйста, прокомментируйте, дайте мне знать, как вы хотите иметь с ними дело.

1 голос
/ 09 марта 2019

Попробуйте это:

awk 'NR>1&& $0 == "text2 valueX"{print a"\n"$0} {a=$0}' input.txt

Обратите внимание, что этот сценарий печатает что-то, только если текущая строка точно соответствует 'text2 valueX'.

1 голос
/ 09 марта 2019

Еще один простой подход с tac и awk.

tac Input_file | awk '$0=="text2 valueX"{print;getline;print}' | tac

Вывод будет следующим.

text1 valueA valueN valueB
text2 valueX
text1 valueC valueN valueD
text2 valueX
text1 valueI valueN valueJ
text2 valueX

Некоторые strace из tac (обработки произвольного файла):

lseek(3, 351051776, SEEK_SET)           = 351051776
read(3, "83,10.1579,56.1257,1412067900\n41"..., 8192) = 8192
write(1, "104,210,84,194,10.1313,56.1528,1"..., 4096) = 4096
write(1, "2092,56.1724,1412068200\n129,20,3"..., 4096) = 4096
lseek(3, 351043584, SEEK_SET)           = 351043584
read(3, "7900\n148,159,77,186,97,10.2090,5"..., 8192) = 8192
write(1, ",140,182,10.1208,56.1784,1412067"..., 4096) = 4096
write(1, "10.1859,56.1239,1412067900\n53,17"..., 4096) = 4096
lseek(3, 351035392, SEEK_SET)           = 351035392

Вы можете увидеть убывающую позицию в lseek.

0 голосов
/ 09 марта 2019

Это может сработать для вас (GNU sed):

sed '$!N;/\ntext2 valueX/p;D' file

Открыть движущееся окно из двух строк по всей длине файла.

Если вторая строка соответствует text2 valueX, выведите обе строки.

Удалить первую строку и повторить.

Для измененного вопроса:

sed '$!N;/\ntext2.*a\.b\./p;D' file

Используйте тот же метод, но представьте новый шаблон как регулярное выражение.

N.B. Новому шаблону могут понадобиться метасимволы для цитирования, например, период должен предшествовать \.

regexp='a\.b\.'
sed '$!N;/\ntext2.*'"$regexp"'/p;D' file
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...