печать с седьмого а-м-т 'б' включительно - PullRequest
0 голосов
/ 29 ноября 2018

Есть ли способ напечатать 4-е совпадение «от четырех» до 8-го совпадения «восьмерки», используя только cat и sed?

Мне дано использовать =, N, p, q, s какнамекает, но не уверен, как использовать эти

Например,

$ cat foo
1
2
3
4
5-
alkjvearv four
four
asdfasd four 
----fourth asdf
qlvkjqrvlj eight
5+
6
7
8
9
eight eight eight
10
11
12 eight
13 eight
eight qorivjqoerijv
----this is eighth
eight
15

$ cat foo | sed ~
----fourth asdf
qlvkjqrvlj eight
5+
6
7
8
9
eight eight eight
10
11
12 eight
13 eight
eight qorivjqoerijv
----this is eighth

это так далеко, как у меня

$ cat foo | sed -n '/four/,/eight/p'
alkjvearv four
four
asdfasd four 
----fourth asdf
qlvkjqrvlj eight

Ответы [ 2 ]

0 голосов
/ 30 ноября 2018

Это может сработать для вас (GNU sed):

sed ':a;h;s/four/&/4;tb;$d;N;ba;:b;s/eight/&/8;tc;$d;N;bb;:c;x;s/.*\n//;G;s/$/\n/;s/^\([^\n]*\n\).*\1/\1/;s/\n$//;q' file

Используется команда подстановки, чтобы проверить, были ли начальные / конечные строки учтены при обработке входного файла.Команда s/someString/&/n сама заменяет n-ное вхождение someString.Команда замены также устанавливает для внутреннего флага значение true, если замена прошла успешно.Команда t позволяет sed проверить внутренний флаг и перейти к другой точке в сценарии команды sed, например, ta перейдет к точке в сценарии sed, где :a происходит, если последняя замена была успешной.Внутренний флаг сбрасывается в false сразу же после перехода или запуска нового цикла sed.Этот механизм используется для подсчета произвольных строк для начальных / конечных условий.После выполнения обоих условий и удаления раздела перед начальной границей обработку входного файла можно прервать, а результат распечатать или не распечатать.

NB Удаление раздела текста перед началомусловие может привести к множеству крайних случаев.Чтобы упростить их, к конечному результату добавляется новая строка, а затем удаляется из нее.

Более простое, но подверженное возможному решению ошибки:

sed -z 's/four/\x00&/4;s/eight/\x00&/8' file |
sed '/\x00four/,/\x00eight/!d;s/\x00\(four\)/\1/;s/\x00\(eight\)/\1/'
0 голосов
/ 29 ноября 2018

Не уверен, что это именно то, что вам нужно, поскольку ваш вопрос довольно неточный, но он может дать вам представление.Конечно, это решение не то, что вы должны использовать (используйте awk).

Строки uuid1 и uuid2 могут быть заменены любыми двумя строками, которых еще нет в файле.

sed -E -e 'H;1h;$!d;x' \
    -e 's/four/uuid1/' -e 's/four/uuid1/' -e 's/four/uuid1/' \
    -e 's/eight/uuid2/' -e 's/eight/uuid2/' -e 's/eight/uuid2/' -e 's/eight/uuid2/' \
    -e 's/eight/uuid2/' -e 's/eight/uuid2/' -e 's/eight/uuid2/' foo |
sed -n '/four/,/eight/p;/eight/q' |
sed 's/uuid1/four/g;s/uuid2/eight/g'

Возвращает:

----fourth asdf
qlvkjqrvlj eight
5+
6
7
8
9
eight eight eight
10
11
12 eight
13 eight
eight qorivjqoerijv
----this is eighth

, что я считаю правильным.

Этот ответ и этот один помог мне.


Объясненная команда:

sed -E -e 'H;1h;$!d;x'

С это

Команды sed H; 1h; $! d; x прочитать весь файл в.

Поскольку вышеупомянутое не использует никакого расширения GNU, оно должно работать на BSD (OSX) sed.Обратите внимание, думал, что этот подход требует sed, который может обрабатывать длинные строки.GNU sed должен быть в порядке.Те, кто использует не-GNU версию sed, должны проверить ее способность обрабатывать длинные строки.

-e 's/four/uuid1/' -e 's/four/uuid1/' -e 's/four/uuid1/' \
-e 's/eight/uuid2/' -e 's/eight/uuid2/' -e 's/eight/uuid2/' -e 's/eight/uuid2/' \
-e 's/eight/uuid2/' -e 's/eight/uuid2/' -e 's/eight/uuid2/' foo

Затем я заменяю первые три four на uuid1 и первые семь eightна uuid2.

Как сказал @JonathanLeffler, если вы увеличите количество замен, становится очень уродливо, но я не нашел обходного пути для версий sed POSIX, я использовал команду из этого ответ .

Если GNU sed недоступен и вы хотите заменить первые 3 вхождения старого на новое, используйте три команды s:

Это хорошо работает, когдаk - небольшое число, но плохо масштабируется до большого k.

sed -n '/four/,/eight/p;/eight/q' - по умолчанию не печатать;от первой four до первой eight выведите строку;когда вы найдете eight, выходите.

Сначала я попробовал: sed -n '/four/,/eight/p', но он мог бы вернуть строки после раздела, который должен быть напечатан.Я использовал этот ответ , чтобы исправить проблему.

Эта команда выбирает линию между первым four и первым eight вхождением.

sed 's/uuid1/four/g;s/uuid2/eight/g' Iзамените uuids на их первоначальные значения.Я делаю это даже для uuid1, поскольку третий four может находиться на той же строке, что и четвертый.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...