Вопрос или проблема
Предположим, у меня есть программа blackbox
и файл со следующим содержимым:
в этом файле
эта строка содержит =TAG=
так же =TAG= и эта строка
как =TAG= делает эта другая строка
эта строка не содержит
и эта строка тоже не
=TAG= снова здесь
снова пропала
Как мне запустить blackbox
только на строках, содержащих =TAG=
?
Примечание 1: Один из способов – использовать цикл while read
, но это считается плохой практикой. Итак, какой канонический, правильный способ это сделать (если такой существует)?
Примечание 2: Конечно, если бы я просто редактировал текст, решение с AWK
или sed
было бы уместным — но blackbox
может иметь желаемые побочные эффекты. Этот вопрос касается тех ситуаций, когда мне нужно выполнить другой процесс.
Примечание 3: Вы можете спросить, что происходит, если blackbox
– это что-то вроде nl
или sort
— когда запуск его на нескольких строках вместе дает другой результат, чем запуск нового процесса на каждой строке. В этом случае я хочу иметь возможность делать это каждым из этих трех способов (используя nl
в качестве примера):
-
Блочно: заменить каждый блок смежных строк, содержащих
=TAG=
, на результатblackbox
для этого блока.в этом файле 1 эта строка содержит =TAG= 2 так же =TAG= и эта строка 3 как =TAG= делает эта другая строка эта строка не содержит и эта строка тоже не 1 =TAG= снова здесь снова пропала
-
Строка за строкой: заменить каждую строку, содержащую
=TAG=
, на результатblackbox
для этой строки.в этом файле 1 эта строка содержит =TAG= 1 так же =TAG= и эта строка 1 как =TAG= делает эта другая строка эта строка не содержит и эта строка тоже не 1 =TAG= снова здесь снова пропала
-
Непрерывно: отправить все строки, содержащие
=TAG=
, в процессblackbox
и заменить каждый блок строками, которые будут распечатаны перед тем, какblackbox
получит следующий блок.в этом файле 1 эта строка содержит =TAG= 2 так же =TAG= и эта строка 3 как =TAG= делает эта другая строка эта строка не содержит и эта строка тоже не 4 =TAG= снова здесь снова пропала
(Здесь, если бы мы использовали
sort
, все совпадающие строки оказались бы отсортированными в последнем совпадающем блоке, потому что они не были бы напечатаны до конца.)
Я не нашел никаких вопросов, касающихся общей проблемы, но это все специальные случаи этой проблемы:
- Как написать скрипт с фигурными скобками, экранированными обратными слэшами (строка за строкой)
- Редактировать файл в зависимости от существования строки (строка за строкой)
- Условно заменить строки файла 1 на соответствующие строки файла 2 (строка за строкой)
- Можно ли ускорить этот bash-скрипт
while read
? (строка за строкой) - Заменить строку содержимым файла с помощью sed (строка за строкой)
- заменить новую строку на пробел по определенному условию с помощью sed (блочно)
- Сортировка блока строк, соответствующих только первой (блочно)
- Удалить строки, соответствующие шаблону, плюс любые строки за ним, соответствующие другому шаблону (блочно)
- Заменить строки, соответствующие шаблону, на строки из другого файла в порядке (непрерывно)
- Что-то вроде `paste`, но с вертикальным выравниванием после разделителя? (непрерывно)
- Передать несколько аргументов командной строки исполняемому файлу с текстовыми файлами (непрерывно)
- Удалить N-ю строку из каждой строки, соответствующей шаблону (непрерывно)
Вот один из способов сделать то, что вы спросили первыми, предположим, blackbox
– это sort -r
:
$ cat tst.sh
#!/usr/bin/env bash
awk '
BEGIN { cmd = "sort -r" }
/=TAG=/ {
print | cmd
next
}
{
close(cmd)
print
}
' "${@:--}"
$ ./tst.sh file
в этом файле
3 как =TAG= делает эта другая строка
2 так же =TAG= и эта строка
1 эта строка содержит =TAG=
эта строка не содержит
и эта строка тоже не
1 =TAG= снова здесь
снова пропала
Если вы хотите сделать это по одной строке, как в вашем 2-м запросе, просто переместите close()
:
$ cat tst.sh
#!/usr/bin/env bash
awk '
BEGIN { cmd = "sort -r" }
/=TAG=/ {
print | cmd
close(cmd)
next
}
{
print
}
' "${@:--}"
Ответ или решение
Запуск программы только на совпадающих строках: пошаговое руководство
Ваша задача состоит в том, чтобы выполнить программу под названием blackbox
только на тех строках файла, которые содержат заданный шаблон =TAG=
. Для этого мы рассмотрим несколько подходов, учитывая разные сценарии: замена строк в зависимости от блока, замена одной строки и непрерывная передача строк.
Предварительные соображения
Прежде чем приступить к реализации, важно отметить, что blackbox
может иметь побочные эффекты. Это необходимый аспект, который следует учитывать, так как простой редактор текста вроде sed
или awk
может не подойти.
Мы также рассмотрим ситуацию, когда blackbox
может быть, например, командой nl
или sort
, и нам нужно знать, как обрабатывать строки для разных сценариев.
Реализация
1. Блочное выполнение
Для замены каждого блока смежных строк, содержащих =TAG=
, мы можем использовать следующий скрипт на awk
:
#!/usr/bin/env bash
awk '
BEGIN { cmd = "sort -r" }
/=TAG=/ {
block = block $0 "\n" # Сбор блока строк, содержащих =TAG=
inBlock = 1
next
}
{
if (inBlock) {
# Если мы вышли из блока, выполните команду на собранном блоке
print block | cmd
close(cmd)
block = "" # Сброс блока
inBlock = 0
}
print # Печатаем строки, не содержащие =TAG=
}
END {
if (inBlock) {
print block | cmd # Обработка последнего блока, если он существует
close(cmd)
}
}
' файл.txt
В этом коде:
- Мы собираем строки с
=TAG=
в блок. - После выхода из блока выполняем команду
blackbox
на собранном блоке.
2. Строковое выполнение
Если вам нужно заменить каждую строку, содержащую =TAG=
, выполните команду для этой строки индивидуально:
#!/usr/bin/env bash
awk '
BEGIN { cmd = "sort -r" }
/=TAG=/ {
print | cmd # Выполняем команду на каждой строке
close(cmd)
next
}
{
print # Печатаем строки, не содержащие =TAG=
}
' файл.txt
В этом случае каждая строка будет обрабатываться отдельно, и результат будет заменен соответствующей строкой.
3. Непрерывное выполнение
Если вам нужно непрерывно передавать строки, используя blackbox
, можно воспользоваться следующим подходом:
#!/usr/bin/env bash
awk '
BEGIN { cmd = "sort -r" }
/=TAG=/ {
print >> "buffer" # Сохраняем строки в буфер
inBuffer = 1
}
{
if (inBuffer) {
# Обрабатываем буфер, как только выходим из блока
close(cmd)
system("cat buffer | " cmd) # Передаем содержимое буфера командной строке
system("rm buffer") # Удаляем буфер
inBuffer = 0
}
print
}
' файл.txt
Этот подход позволяет вам собрать все строки с совпадением в буфер и обработать их последовательно, сохраняя порядок.
Заключение
В результате, любой из предложенных методов очень гибок и может быть легко адаптирован под ваши нужды. Выбор подхода зависит от того, как вы хотите обрабатывать строки: индивидуально, блоками или непрерывно. С помощью awk
вы можете эффективно взаимодействовать с файлами, обеспечивая высокую производительность и надежность обработки данных.