Вот еще простой sed:
sed '/#nvram = \[/,/#]/ s/#]/#]\nfoobar/' file
Он находит строку, в которой встречается #nvram = [
, а затем все строки после нее и до тех пор, пока не будет адресовано первое вхождение #]
, затем вы заменяете #]\nfoobar
на #]
.
Это было протестировано с GNU Awk 5.1.0, API :3.0. Из-за использования 4-го аргумента в split
это решение может не работать в других версиях, несовместимых с используемым здесь синтаксисом.
awk '{n=split($0, a, " ", b); line=""; for (i = 1; i <= n; i++) { if (i < 5 || a[i] < $4) line=(line a[i] b[i])}; print line; }' file.txt
Пояснение:
n=split($0, a, " ", b);
-это разбивает всю строку($0
)на значения (, хранящиеся в a
), и пробелы (, хранящиеся в b
), поэтому мы можем попытаться сохранить форматирование исходного файла. Значение, хранящееся в n
, дает нам количество полей для обработки каждой строки. split
массивы a
и b
индексы начинаются с 1. line=""
-начать со строки как пустую строку for (i = 1; i <= n; i++)
-позволяет выполнить итерацию по каждому полю, разделение начинается с индекса 1, так же как и наш цикл.Часть <=
обеспечивает обработку последнего (n-го )поля if (i < 5 || a[i] < $4)
-условие истинно для первых 4 полей или всякий раз, когда значение поля меньше четвертого поля (требуемое условие)line=(line a[i] b[i])
-объединить фактические поля и пробелы с предыдущими, которые удовлетворяют требованиям условия «если» print line
-выводит line
переменную, содержащую желаемый результат Если вас не волнуют пробелы в выводе, все, что вам нужно, это:
$ cat tst.awk
{
out = $1 OFS $2 OFS $3 OFS $4
for (i=5; i<=NF; i++) {
if ( $i < $4 ) {
out = out OFS $i
}
}
print out
}
$ awk -f tst.awk file
NC_000001.11_NM_001005484.2 69270 234 69037 65565
NC_000001.11_NM_001005484.2 69511 475 69037 65565
NC_000001.11_NM_001005484.2 69761 725 69037 65565
NC_000001.11_NM_001385640.1 942155 20 942136 924432 925922 930155 931039 935772 939040 939272 941144
, который вы можете подключить к column
для визуального выравнивания, если хотите:
$ awk -f tst.awk file | column -t
NC_000001.11_NM_001005484.2 69270 234 69037 65565
NC_000001.11_NM_001005484.2 69511 475 69037 65565
NC_000001.11_NM_001005484.2 69761 725 69037 65565
NC_000001.11_NM_001385640.1 942155 20 942136 924432 925922 930155 931039 935772 939040 939272 941144
В противном случае, если вы хотите, чтобы интервал в выводе выглядел так же, как интервал во вводе (, т. е. как 1 или более пробелов для первых 4 полей и 2 или более для остальных полей )и предполагая, что в некоторых строках может быть только 4 или меньше полей, а затем использовать любой POSIX awk (для классов символов и интервалов регулярных выражений):
$ cat tst.awk
BEGIN { OFS="\t" }
match($0,/([^[:space:]]+[[:space:]]+){3}[^[:space:]]+/) {
out = substr($0,RSTART,RLENGTH)
for (i=5; i<=NF; i++) {
if ( $i < $4 ) {
out = out OFS $i
}
}
$0 = out
}
{ print }
Если поля после $4 должны быть разделены табуляцией -:
$ awk -f tst.awk file
NC_000001.11_NM_001005484.2 69270 234 69037 65565
NC_000001.11_NM_001005484.2 69511 475 69037 65565
NC_000001.11_NM_001005484.2 69761 725 69037 65565
NC_000001.11_NM_001385640.1 942155 20 942136 924432 925922 930155 931039 935772 939040 939272 941144
или если они должны быть разделены пробелами:
$ awk -f tst.awk file | column -s$'\t' -t
NC_000001.11_NM_001005484.2 69270 234 69037 65565
NC_000001.11_NM_001005484.2 69511 475 69037 65565
NC_000001.11_NM_001005484.2 69761 725 69037 65565
NC_000001.11_NM_001385640.1 942155 20 942136 924432 925922 930155 931039 935772 939040 939272 941144
В приведенном выше примере сохраняется пробел между первыми 4 полями, так что это будет любая комбинация табуляций и/или пробелов, которые у вас есть при вводе, а затем печатается табуляция перед каждым 5-м и последующим полем, которое вы можете использовать column
, чтобы при желании заменить на эквивалентные пробелы, оба из которых выглядят как ввод и вывод в вашем вопросе.
Я создаю новую строку с именем out
в циклах выше и назначаю ее $0
один раз после циклов, а не изменяю $0
или $i
внутри циклов, потому что каждый раз, когда вы меняете $i
awk должен повторно -строить $0
из своих полей, и каждый раз, когда вы меняете $0
, awk должен повторно разбивать $0
на поля, поэтому и то, и другое неэффективно и может привести к непредвиденным ошибкам в зависимости от содержимого полей и поэтому вы не должны изменять $0
или $i
внутри цикла, если только у вас нет конкретной цели, которая требует от вас этого.