Что мне помогло, так это установка xauth, после чего все заработало как шарм!
С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, весь файл будет храниться в памяти напрасно.
Единственным способом обойти это было бы дважды обработать файл, но, конечно, это можно было бы сделать только тогда, когда ввод является обычным файлом (, а не конвейером, например ).
Это можно сделать следующим образом:
$ sed -e '
/BEGIN/,/END/!d
H;/BEGIN/h;/END/!d;g
' inp
Как это работает, для начального/конечного диапазона строк он сохраняет их в удерживаемом пространстве. Затем удаляет, пока не встретите строку END. В этот момент мы вспоминаем, что находится в трюме. OTW, мы ничего не получаем. ХТН.
cat input |
sed '/\*\*\*\*\* BEGIN \*\*\*\*\*/,/\*\*\*\*\* END *\*\*\*\*/ p;d' |
tac |
sed '/\*\*\*\*\* END \*\*\*\*\*/,/\*\*\*\*\* BEGIN *\*\*\*\*/ p;d' |
tac
Это работает, когда tac
переворачивает строки так, чтобы sed
мог найти оба разделителя в обоих порядках.
Подход 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
Использование 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
. &&
("И")Оператор 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}"