#bash #shell #awk #sed
#bash #оболочка #awk #sed
Вопрос:
Я ищу замену строк в файле. т.е., Если «oldtext» находится в файле в начале строки, замените всю строку на «newtext».
Начало строки может иметь ^oldtext
или oldtext
будет иметь отступ с некоторыми пробелами / табуляциями
grep "^[S]oldtext" myfile.txt # doesn't work
Мне нужно вычислить тот же уровень отступа, что и у «oldtext»
prefixspaces = <number of spaces before the "mytext", converting tabs to 4 spaces>
Я понимаю, что sed, возможно, лучший способ добиться этого, но мне как-то нужно сначала вычислить пространство префиксов, затем мой вывод выглядит примерно так:
sed -i -e 's/^$prefixspaces$newtext*$/$prefixspaces$newtext/g' myfile.txt
Не могу понять, как это вычислить. $prefixspace
Может быть, его можно хранить в группе ()
или что-то в этом роде, чтобы sed мог легко вычислять и работать с ним? Возможно, это однострочный sed или awk, но я не могу разобраться с этим после некоторого поиска.
Комментарии:
1. Не могли бы вы также опубликовать образец ввода и ожидаемого результата в своем вопросе, чтобы сделать его более понятным.
2.
s/^([[:space:]]*)oldtext/1$newtext/
?3. Это здорово, @Shawn, я добавил
.*
после oldtext, чтобы он заменял всю строку, и хотел, чтобы все пробелы были, поэтому изменил его наs*
в начале строки. Работает хорошо.4. Вы должны проверить ответы, которые вы получили, когда
oldtext
содержат метасимволы регулярных выражений иnewtext
содержат обратные ссылки. Например, попробуйте их, когдаoldtext
естьa.c
, и входной файл содержит обаa.c
иabc
, и когдаnewtext
естьdamp;e
. Вы должны выполнять буквальное сопоставление строк и замены буквенных строк, а не сопоставление регулярных выражений и замены строк с поддержкой обратной ссылки, которые поддерживают все, что поддерживает sed, и пока все ответы.5. хорошо, у вас есть способ исправить это изменение?
Ответ №1:
Вот так:
sed 's/^( *)oldtext.*/1newtext/' file
Объяснение:
Поиск
^ beginning of the line
( *) capture 0 or more spaces in group 1
oldtext 'oldtext'
.* rest of the line
заменить
1 the 0 or more spaces from group1
newtext 'newtext'
Ответ №2:
С sed
Другой способ сделать, дополнительно к принятому ответу, — использовать символы класса ([[:пробел:]]) и расширяющие регулярные выражения с -r
параметром:
$ sed -r 's/^([[:space:]]*)oldtext.*/1newtext/' << _eof
oldtext this
a
oldtext also this
_eof
И результат будет:
newtext
a
newtext
В ([[:space:]]*)
, мы захватили группу с нулем или более пробелов, но мы можем указать определенное число.
С awk
Мы можем использовать gsub
для замены пробелов и подсчета времени:
$ awk
-v old="oldtext"
-v new="newtext"
'BEGIN{re="^[[:space:]]*"old}
{
if (match($0,re)) {
i=gsub(/ /,"")
while (--i) printf " "
print new
}
else
print
}' << _eof
oldtext this
oldtext also this
oldtext and this
oldtext also this
_eof
И результат будет:
newtext
newtext
newtext
newtext
С perl
Мы можем достичь этого с помощью perl
в стиле, подобном sed:
$ perl -lpe 's/^(s*)oldtext.*/1newtext/' << _eof
oldtext this
oldtext this
oldtext this
oldtext also this
_eof
И результат будет:
newtext
newtext
newtext
newtext
Ответ №3:
Это может сработать для вас (GNU sed):
sed '/^s*oldtext/s/S.*/newtext/' file
Сопоставление oldtext
в начале строки или с отступом и замена с первого символа, не являющегося пробелом.