Печатать линии между начальным и конечным шаблонами, но если конечный шаблон не существует, не печатать

Что мне помогло, так это установка xauth, после чего все заработало как шарм!

6
07.06.2019, 03:03
6 ответов

Сpcregrep:

pcregrep -M '(?s)BEGIN.*?END'

Это также работает, если BEGIN и END находятся в одной строке, но не в таких случаях, как:

BEGIN 1 END foo BEGIN 2
END

Где pcregrepловит первого BEGIN 1 END, но не второго.

Чтобы справиться с ними, с помощью awkвы можете:

awk '
  !inside {
    if (match($0, /^.*BEGIN/)) {
      inside = 1
      remembered = substr($0, 1, RLENGTH)
      $0 = substr($0, RLENGTH + 1)
    } else next
  }
  {
    if (match($0, /^.*END/)) {
      print remembered $0
      if (substr($0, RLENGTH+1) ~ /BEGIN/)
        remembered = ""
      else
        inside = 0
    } else
      remembered = remembered $0 ORS
  }'

На входе типа:

a
BEGIN blah END BEGIN 1
2
END
b
BEGIN foo END
c
BEGIN
bar
END BEGIN
baz END
d
BEGIN
xxx

Дает:

BEGIN blah END BEGIN 1
2
END
BEGIN foo END
BEGIN
bar
END BEGIN
baz END

Оба должны хранить в памяти все, начиная с BEGIN и заканчивая следующим END. Поэтому, если у вас есть огромный файл, первая строка которого содержит BEGIN, но без END, весь файл будет храниться в памяти напрасно.

Единственным способом обойти это было бы дважды обработать файл, но, конечно, это можно было бы сделать только тогда, когда ввод является обычным файлом (, а не конвейером, например ).

5
27.01.2020, 20:20

Это можно сделать следующим образом:

$ sed -e '
    /BEGIN/,/END/!d
    H;/BEGIN/h;/END/!d;g
' inp

Как это работает, для начального/конечного диапазона строк он сохраняет их в удерживаемом пространстве. Затем удаляет, пока не встретите строку END. В этот момент мы вспоминаем, что находится в трюме. OTW, мы ничего не получаем. ХТН.

10
27.01.2020, 20:20
cat input |
sed '/\*\*\*\*\* BEGIN \*\*\*\*\*/,/\*\*\*\*\* END *\*\*\*\*/ p;d' | 
tac |
sed '/\*\*\*\*\* END \*\*\*\*\*/,/\*\*\*\*\* BEGIN *\*\*\*\*/ p;d' |
tac

Это работает, когда tacпереворачивает строки так, чтобы sedмог найти оба разделителя в обоих порядках.

7
27.01.2020, 20:20

Подход GNU awk. Результат достигается установкой определенных переменных при обнаружении начального заголовка. Некоторые переменные можно сократить для удобства

$ awk '/BEGIN/{a[i++]=$0;flag=1;next};flag==1{a[i++]=$0;if($0~/END/){print_array=1; nextfile;} }; END{if(print_array) for(j=0;j<=i;j++)print a[j]}' input.txt
***** BEGIN *****
BASH is awesome
BASH is awesome
***** END *****

При отсутствующем флаге END результат нулевой, как и ожидалось:

$ awk '/BEGIN/{a[i++]=$0;flag=1;next};flag==1{a[i++]=$0;if($0~/END/){print_array=1; nextfile;} }; END{if(print_array) for(j=0;j<=i;j++)print a[j]}' input2.txt
2
27.01.2020, 20:20

Использование sed:

sed '/BEGIN/{b t}; d; :t {N; /END/{p; d;}; b t}'

Пояснение:

  • /BEGIN/{b t};-при совпадении /BEGIN/переключитесь на ветвь с меткой t.
  • d;-для других строк удалить и пропустить оставшиеся команды
  • :t-ветвь с маркировкойt
  • {N; /END/{p; d;}; b t}
    • N-прочитать следующую строку, добавить ее к текущему пространству шаблонов, затем
    • для строк, соответствующих /END/, вывести накопленные данные; пропустить остальные инструкции
    • вернуться к ответвлению t.
3
27.01.2020, 20:20

Используйте оператор bash &&("И")

Оператор bash &&объединяет две команды. Он запускает вторую команду только в том случае, если первая команда возвращает статус выхода 0. Преимущество использования &&для условной цепочки команд заключается в том, что это быстрый и простой -до -метод запоминания для создания сценариев оболочки,по сравнению со сложным синтаксисом, который может потребоваться для выполнения задачи за один проход одной команды.

Поскольку статус выхода grepможет быть 0 (, когда он находит совпадающий шаблон ), или 1 (, когда он не находит совпадения ), вы можете использовать grepи &&для проверки файла на наличие шаблона перед печатью любых строк:

file="file.txt" ; grep -q -E '^\*{5} END \*{5}$' "${file}" && sed -n -r '/^\*{5} BEGIN \*{5}$/,/^\*{5} END \*{5}$/p' "${file}"

ПРЕДОСТЕРЕЖЕНИЕ:В этом примере предполагается, что шаблон BEGIN появится перед шаблоном END. Это может быть безопасным предположением, поскольку в вопросе не показаны примеры, в которых END встречается перед BEGIN. Если надежный метод устранения осложнений не нужен, время разработчика лучше потратить на другие задачи.

Тот же код, отформатированный для удобства чтения:

file="file.txt"

grep -q -E '^\*{5} END \*{5}$' "${file}" && \
sed -n -r '/^\*{5} BEGIN \*{5}$/,/^\*{5} END \*{5}$/p' "${file}"

В этом примере -qуказывает grepне печатать вывод; это не влияет на коды выхода. -Eсообщает grep, что в данном случае мы используем расширенные регулярные выражения (, чтобы сократить \*\*\*\*\*до\*{5}).

Если grepобнаруживает шаблон END, выполняется команда sed. -rделает для sedто, что -Eделает для grep. Использование -nс pуказывает sedпечатать из строки, содержащей шаблон BEGIN, в строку, содержащую шаблон END, как вы пытались в вопросе.

Если звездочки и пробелы в шаблонах BEGIN и END не имеют значения, код становится короче:

file="file.txt" ; grep -q 'END' "${file}" && sed -n '/BEGIN/,/END/p' "${file}"

Тот же более короткий пример, отформатированный для удобства чтения:

file="file.txt"

grep -q 'END' "${file}" && \
sed -n '/BEGIN/,/END/p' "${file}"
-1
27.01.2020, 20:20

Теги

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