Вывести второе или n-е совпадение поиска sed, основанного на двух шаблонах

Я хотел бы напечатать n-е совпадение поиска sed, которое основано на двух шаблонах, как показано ниже:

sed -n '/start here/,/end here/p'  'testfile.txt' 

Скажем, что testfile.txt содержит текст ниже:

[ 111]

и что я не хочу печатать нули между двумя шаблонами.

На основе приведенной выше команды я получу все совпадения между шаблонами, а ее вывод показан ниже:

start here
0000000
0000000
end here
start here
123
1234
12345

123456
end here
start here
00000000
end here

В то время как мой желаемый результат:

start here
123
1234
12345

123456
end here

Учтите, что строки должны быть напечатаны как в testfile.txt, а не соединены.

5
задан 17 May 2019 в 13:02

2 ответа

Я просто переключился бы на другой инструмент. Perl, например:

perl -ne '$k++ if /Pattern1/; if(/Pattern1/ .. /Pattern2/){print if $k==3}' file

Это распечатает 3-е соответствие. Изменитесь $k==3 к любому значению Вы хотите. Логика:

  • $k++ if /Pattern1/ : увеличьте значение переменной $k тем, если эта строка соответствует Pattern1.
  • if(/Pattern1/ .. /Pattern2/){print if $k==3} : если эта строка в диапазоне /Pattern1/ кому: /Pattern2/, распечатайте его, но только если $k 3. Измените это значение на то, какой бы ни соответствие Вы хотите.

Вы могли перенести это в небольшую функцию оболочки, чтобы смочь получить Энное соответствие более легко:

getNth(){
  pat1="$1"
  pat2="$2"
  n="$3"
  file="$4"

  perl -ne '$k++ if /'"$pat1"'/;if(/'"$pat1"'/ .. /'"$pat2"'/){print if $k=='"$n"'}' file

}

Вы могли затем выполнить его как это:

getNth Pattern1 Pattern2 3 'huge file.txt' 

Используя Ваши данные в качестве примера:

$ perl -lne '$k++ if /start here/;if(/start here/ .. /end here/){print if $k==2}' testfile.txt
start here
123
1234
12345

123456
end here

Или:

$ getNth 'start here' 'end here' 2 testfile.txt
start here
123
1234
12345

123456
end here

Только для забавы, вот другой подход жемчуга:

$ perl -lne '($k++,$l++) if /start here/; print if $l && $k==2; $l=0 if /end here/' testfile.txt 
start here
123
1234
12345

123456
end here

Или, если Вам нравится играть в гольф (благодарит @simlev):

perl -ne 'print if /^start here$/&&++$k==2../^end here$/' testfile.txt 
5
ответ дан 17 May 2019 в 13:02

Я бы решил это с Perl, как разумно предполагает @terdon . Или с AWK:

awk '/start here/&&++k==2,/end here/' testfile.txt

Если бы мне пришлось использовать sed в одиночку (как указывает OP в комментарии), я бы придумал что-то гораздо более запутанное, менее читаемое и менее настраиваемое:

[ 111]
0
ответ дан 17 May 2019 в 13:02

Другие вопросы по тегам:

Похожие вопросы: