Как заменить новые строки между скобками

#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
    }
}