Если вы хотите найти все слова длиной 64 из /path/to/file
, вы можете использовать
tr -c '[:alnum:]' '\n' < /path/to/file | grep '^.\{64\}$'
Это заменяет все не -буквенно-цифровые символы символами новой строки, поэтому каждое слово находится на отдельной строке. Затем он фильтрует этот результат, чтобы включить только слова длины 64.
awk '/^ABC/ && pre { print dpre ORS $0; pre=""; next }
{ if(pre) print pre; pre=dpre=$0; sub(/ {0,4}/, "END ", dpre) }
END{ if(pre) print dpre }' infile
Первый блок будет выполняться только в том случае, если строка начинается со строкиABC
и когда также была установлена временная переменная pre
, иначе будет выполнен следующий блок.
блок END{...}
будет выполнен только один раз и после завершения всех.
для первой строки, конечно, все ещеpre
переменная еще не установлена, поэтому будет выполнен второй блок, и он делает следующее:
если внутри есть что-то pre
напечатайте сначалаif(pre) print pre
(этим мы откладываем печать предыдущей строки, чтобы проверить, начинается ли следующая строка с ABC
или нет, потому что нам нужно добавить END
впереди этой линии)
затем мы копируем эту строку, скажем, в две отдельные переменные pre
иdpre
(одна будет нетронутой (позже нам нужно напечатать ее нетронутой ), а для другой в sub(/ {0,3}/,"END ", dpre)
мы добавляем END
строка в dpre
.
Обратите внимание, что с {0,4}
(ноль или максимум 4 пробела; 4 получается из длины END<SPC>
), мы гарантируем, что строка END
всегда будет начинаться, а также предотвращаем усечение исходного значения строки, если пробелов вообще не было.
Ниже вы можете проследить каждую итерацию команды для собственного понимания:
ABC
(/^ABC/
)? pre
? dpre
, затем одну новую строку ORS
, а затем саму текущую строку pre=""
и переход к REPEAT из-за оператора next
говорит об этом. pre
? pre
это установлено в "if(pre) print pre
"; pre=dpre=$0
; END
строку dpre
. pre=dpre=$0
; END
для dpre
. dpre
, если она была установлена, иначе перейти к REPEAT . $ cat tst.awk
NF == 1 { sub(/^ /,"END",prev) }
NR > 1 { print prev }
{ prev = $0 }
END { sub(/^ /,"END",prev); print prev }
$ awk -f tst.awk file
ABC
2 3 4
7 9 4
END 1 2 5
ABC
13 11 17
END 2 1 1
ABC
7 9 14
5 8 2
9 9 9
END 7 1 2
Шаг 1:
for i in $(awk '/ABC/ {print NR-1}' filename| awk '$1 != "0"');
do
sed -i ''$i's/.*/END &/g' filename;
done
Шаг 2:
sed '$s/.*/END &/g' filename
POSIX sed
с отключенной автопечатью шаблонного пространства(-n
)
sed -ne '
/ABC/!{x;1!p;$!d;}
x;1!s/^ \{0,3\}/END&/p
${x;/ABC/p;}
' file
ABC
2 3 4
7 9 4
END 1 2 5
ABC
13 11 17
END 2 1 1
ABC
7 9 14
5 8 2
9 9 9
END 7 1 2
Вышеприведенный код sed расширен и прокомментирован.
sed -ne '
# if we see a non boundary line...
/ABC/!{
x; # store it n retrieve prev line
1!p; # print the prev line if not first (obviously)
$!d; # printed prev so go back n read next line unless we are @eof(for which see below...)
}
x; # retrieve prev
1!s/^ \{0,3\}/END&/p; # add marker
${x;/ABC/p;}
# To account for a trailing ABC
' file
Другой sed
подход:
1 { # First line of data.
h; # Hold current line.
d; # Skip to next cycle.
}
/^ABC$/ { # An "ABC" line.
x; # Swap in previous line.
s/.../END/p; # Add "END" at start of line & print.
d; # Skip to next cycle.
}
x; # Swap current and previous lines.
# Previous line now in pattern space,
# current line in hold space.
$ { # Last line of data.
p; # Print previous line.
g; # Get current line from hold space.
s/.../END/; # Add "END" at start of line.
}
# (implicit print)
Это удерживает текущую строку в области хранения, пока не будет прочитана следующая строка. Только тогда мы узнаем, нужно ли нам добавлять END
к строке или нет перед ее печатью. Только когда мы добираемся до самой последней строки входных данных, мы знаем, что нам нужно добавить END
к текущей строке, и мы можем напечатать как предыдущую, так и текущую строку в одном и том же цикле.
Мой подход предполагает, что входные данные содержат по крайней мере две строки ввода и что последняя строка не ABC
.
В командной строке:
sed -e '1{h;d;}' -e '/^ABC$/{x;s/.../END/p;d;}' -e 'x' -e '${p;g;s/.../END/;}'
Perl можно использовать в этом сценарии, и благодаря его мощным возможностям регулярных выражений он может разобраться с ним в истинном -лайнере.
perl
в режиме slurp -0777
с включенной автоматической печатью текущей записи -p
мы проверяем все строки, за которыми следует строка ABC или eof. В обоих сценариях вставляется строка «END» в начале, перезаписывая до 3 начальных пробельных символов.
perl -0777pe '
s/^(?!ABC)\h{0,3}(?=.*\n(?:ABC|\z))/END/mg;
' file
Изучение регулярного выражения:
^(?!ABC)
\h{0,3}
(?=.*\n(?:ABC|\z)
и оттуда на следующую строку, которая начинается с ABC или это eof.