Удалить символы между двумя шаблонами, используя sed - PullRequest
1 голос
/ 19 января 2020

Ниже приведен вариант использования, в котором мне нужно удалить некоторые специальные символы (", /, \) с помощью sed.

sample.txt

srcs : [a.c] cflags : [abcd@ef]
srcs : ["b.c"] cflags : [ab\cd"ef]
srcs : [r/.c] cflags : [a""bcd*ef""]
srcs : [g.c] cflags : [ab/cd*ef]

Необходимо удалить (\, ", /) только из записи cflags в каждой строке. Ожидаемый результат:

srcs : [a.c] cflags : [abcd@ef]
srcs : ["b.c"] cflags : [abcdef]
srcs : [r/.c] cflags : [abcd*ef]
srcs : [g.c] cflags : [abcd*ef]

Механизм подстановки попыток sed с регулярным выражением, который ищет строку между "cflags" и "]", которая возвращает строки между cflags и]:

cat sample.txt | sed 's/cflags : \(.*\)]/\1/'

srcs : [a.c] [abcd@ef
srcs : ["b.c"] [ab\cd"ef
srcs : [r/.c] [a""bcd*ef""
srcs : [g.c] [ab/cd*ef

Замещается на '' но он удаляет всю запись cflags:

cat sample | sed 's/cflags : \(.*\)]/''/'

srcs : [a.c]
srcs : ["b.c"]
srcs : [r/.c]
srcs : [g.c]

Ищет регулярное выражение, которое может найти (\, ", /) между cflags и ']' в каждой строке, а затем его можно просто удалить с помощью sed.

Ответы [ 4 ]

2 голосов
/ 19 января 2020

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

sed -E ':a;s/(.*cflags.*)["\\/]/\1/;ta' file

Сохраняйте все до и включая cflags в строке и удаляйте все символы \, / или " после этого.

Если необходимо изменить только строку между второй парой квадратных скобок, используйте:

sed -E ':a;s/(.*cflags[^[]*\[[^]]*)[\\/"]/\1/;ta' file
1 голос
/ 19 января 2020

Не просто в sed, но возможно в Perl:

perl -pe '
    s{cflags : \[\K([^]]*\])}{
        $1 =~ s,[\\/"],,gr
    }e' -- sample.txt
  • -p читает строку ввода построчно и печатает результаты
  • s{pattern}{replacement} is похож на sed s///, но более мощный
  • модификатор e интерпретирует замену как код
  • \K, который забывает все совпадения, поэтому часть cflags совпадает, но не replace
  • модификатор r возвращает результат замещения вместо изменения переменной на месте
1 голос
/ 19 января 2020

Не могли бы вы попробовать следующее, если вы в порядке с awk здесь:

awk '
match($0,/cflags[^]]*\]/){
  val=substr($0,RSTART,RLENGTH)
  gsub(/\\|,|"|\//,"",val)
  print substr($0,1,RSTART-1) val substr($0,RSTART+RLENGTH)
  val=""
}
'  Input_file

Объяснение вышеуказанного кода:

awk '                                                          ##Starting awk program from here.
match($0,/cflags[^]]*\]/){                                     ##Using match to match regex from cflags till ] here.
  val=substr($0,RSTART,RLENGTH)                                ##Creating variable val which is sub-string of RSTART and RLENGTH values.
  gsub(/\\|,|"|\//,"",val)                                     ##Globally substituting \,"/ with NULL in variable val here.
  print substr($0,1,RSTART-1) val substr($0,RSTART+RLENGTH)    ##Printing before part, actual part and last part of lines here,in this program.
  val=""                                                       ##Nullifying variable val here.
}
'  Input_file                                                  ##Mentioning Input_file name here.

Вывод будет следующим.

srcs : [a.c] cflags : [abcd@ef]
srcs : ["b.c"] cflags : [abcdef]
srcs : [r/.c] cflags : [abcd*ef]
srcs : [g.c] cflags : [abcd*ef]
0 голосов
/ 19 января 2020

Вы не можете применить регулярное выражение только к части строки в sed. Таким образом, метод, чтобы сделать это, состоит в том, чтобы держать линию в удерживающем пространстве. Затем извлеките часть строки, которую вам нужно применить регулярное выражение. Затем примените регулярное выражение - ie. удалите символы " / \. Затем возьмите строку из пространства удержания и перетасуйте ее, чтобы заменить часть строки, которую вы хотите заменить, замененной частью (ох, я надеюсь, что это имеет смысл).

Следующий скрипт:

cat <<'EOF' |
srcs : [a.c] cflags : [abcd@ef]
srcs : ["b.c"] cflags : [ab\cd"ef]
srcs : [r/.c] cflags : [a""bcd*ef""]
srcs : [g.c] cflags : [ab/cd*ef]
EOF
sed '
    # hold the line
    h
    # remove everything before clags
    s/.*cflags : //
    # replace the " \ / for nothing, ie. remove them
    # alternatively s/\("\|\\\|\/\)//g or s@\("\|\\\|/\)@@g 
    # but I think the following is more readable
    s/"//g
    s/\\//g
    s/\///g
    # append the holded line
    G
    # shuffle the pattern space for the output
    s/\(.*\)\n\(.*\)cflags : .*/\2cflags : \1/
'

выходов на репле :

srcs : [a.c] cflags : [abcd@ef]
srcs : ["b.c"] cflags : [abcdef]
srcs : [r/.c] cflags : [abcd*ef]
srcs : [g.c] cflags : [abcd*ef]

и однострочный:

sed 'h;s/.*cflags : //;s/"//g;s/\\//g;s/\///g;G;s/\(.*\)\n\(.*\)cflags : .*/\2cflags : \1/'
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...