Запускать программу только на совпадающих строках

Вопрос или проблема

Предположим, у меня есть программа 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, все совпадающие строки оказались бы отсортированными в последнем совпадающем блоке, потому что они не были бы напечатаны до конца.)

Я не нашел никаких вопросов, касающихся общей проблемы, но это все специальные случаи этой проблемы:

Вот один из способов сделать то, что вы спросили первыми, предположим, 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 вы можете эффективно взаимодействовать с файлами, обеспечивая высокую производительность и надежность обработки данных.

Оцените материал
Добавить комментарий

Капча загружается...