#linux #awk #sed #grep #logfile
Вопрос:
У меня есть файл журнала, аналогичный этому формату
test {
seq-cont {
0,
67,
266
},
grp-id 505
}
}
test{
test1{
val
}
}
Вот команда echo для получения этого вывода
$ echo -e "test {nseq-cont {nttt0,nttt67,nttt266nttt},nttgrp-id 505nt}n}ntest{nttest1{nttvalnt}n}n"
Вопрос в том, как удалить все пробелы между seq-cont {
и следующим }
, которых может быть несколько в файле.
Я хочу, чтобы результат был таким. Предпочтительно использовать sed для получения выходных данных.
test{seq-cont{0,67,266},
grp-id 505
}
}
test{
test1{
val
}
}
Усилия OP: Вот тот, который несколько сработал, но не совсем то, что я хотел:
sed ':a;N;/{/s/[[:space:]] //;/}/s/}/}/;ta;P;D' logfile
Комментарии:
1. Почему новые строки были удалены после
266
, но не после505
, несмотря на то, что они оба находятся «между скобками»? Это только для ввода «между самыми внутренними скобками»2. Да, это так. Между первыми соответствующими открытыми и закрытыми скобками
3. @RamananT, также, пожалуйста, добавьте свой проверенный код в качестве ваших усилий в своем вопросе, который настоятельно рекомендуется на SO.
4. Попробуй
echo -e "test {seq-cont {0,67,266},nttgrp-id 505nt}n}ntest{nttest1{nttvalnt}n}n"
5. @RavinderSingh13, Вот тот, который несколько сработал, но не совсем то, что я хотел: sed ‘:a;N;/{/s/[[:пробел:]] //;/}/s/}/}/;ta;P;D’
Ответ №1:
Это можно сделать gnu-awk
с помощью пользовательского RS
регулярного выражения, которое соответствует {
и закрывается }
:
awk -v RS='{[^}] }' 'NR==1 {gsub(/[[:space:]] /, "", RT)} {ORS=RT} 1' file
test {seq-cont{0,67,266},
grp-id 505
}
}
test{
test1{
val
}
}
Здесь:
NR==1 {gsub(/[[:space:]] /, "", RT)}
: Для первой записи замените все пробелы (включая разрывы строк) пустой строкой.{ORS=RT}
: УстановитеORS
значение для любого текста, который мы захватили вRS
PS: Удалите NR==1
, если вы хотите сделать это для всего файла.
Ответ №2:
С показанными вами образцами, пожалуйста, попробуйте следующую awk
программу. Протестировано и написано на GNU awk
.
awk -v RS= '
match($0,/{nseq-cont {n[^}]*/){
val=substr($0,RSTART,RLENGTH)
gsub(/[[:space:]] /,"",val)
print substr($0,1,RSTART-1) val substr($0,RSTART RLENGTH)
}
' Input_file
Объяснение: Простым объяснением было бы использование RS
возможности установить его равным нулю. Затем используйте match
функцию awk
, чтобы сопоставить все между seq-cont {
до следующего появления }
. Удаление всех пробелов, новых строк в сопоставленном значении. Наконец, распечатайте все значения, включая недавно отредактированные значения, чтобы получить ожидаемый результат, упомянутый OP.
Ответ №3:
Вы можете сделать это намного проще с помощью perl
:
perl -0777 -i -pe 's/s (seq-conts*{[^}]*})/$1=~s|s ||gr/ge' logfilepath
Этот -0777
параметр говорит perl
хлебать файл в одну строку, -i
сохраняет изменения рядный, s (seq-conts*{[^}]*})
регулярное выражение соответствует одному или более пробелов, а затем захватывает в группу 1 ( $1
) seq-cont
, ноль или более пробелов, а затем подстроку между крайней левой {
и следующей }
случайной работы ( [^}]*
соответствует нулю или более символов, чем другой }
) а потом все, один или более пробельных символов пароля (сочетается с s
) удаляются из всей группы 1 значение ( $1
) (это второй внутренний замены включен с e
флагом). Все вхождения обрабатываются с g
помощью флага (рядом e
).
Смотрите онлайн-демонстрацию:
#!/bin/bash
s=$(echo -e "test {nseq-cont {nttt0,nttt67,nttt266nttt},nttgrp-id 505nt}n}ntest{nttest1{nttvalnt}n}n")
perl -0777 -pe 's/s (seq-conts*{[^}]*})/$1=~s|s ||gr/ge' <<< "$s"
Выход:
test {seq-cont{0,67,266},
grp-id 505
}
}
test{
test1{
val
}
}