LINUX.ORG.RU

Замена по шаблону


0

0

Озадачился следующим: у меня есть строка, содержащая имя файла. Надо в указанном файле:строчке выкинуть " [это имя файла]", если оно там есть. Для sed:

s/'/'\\''/ for ($filename, $infofile);
qx|sed -E -i.bak -e '${lineno}s/ \[$filename\]//' '$infofile'|;
Для perl:
s/'/'\\''/ for ($filename, $infofile);
qx|perl -p -i'*.bak' -e 's/\Q [$filename]\E// if \$.==$lineno;' '$infofile'|;
Но не понимаю как эскейпить переменную $filename, она ведь даже при \Q может сама \E содержать? Или может есть другой способ заменить конкретный текст в конкретной строке файла?

Щас вот только подумал про это, но как-то криво выглядит:

qx|perl -pe 'index(\$_,'\''$filename'\'') < 0 or ...'|;

Всем заранее благодарен.

Пока не придумал ничего умнее:

my $filename = "dir/test['1'].txt";
$filename =~ s/'/'\\''/g;
$filename =~ s|/|\\/|g;
my $command = q{'$t=q/}.$filename.q{/;s/\Q [$t]\E//;'};

print "$command\n";
system "echo $command";
#system "perl -pe $command";

arturpub ★★
() автор топика
Ответ на: комментарий от vsn

До чего дожили и при чем тут питон, прости? Я так-то на перле пишу, просто не хочу заморачиваться для этой операции отдельным скриптом, неудобно его будет с собой таскать. Задача решена, мне интересно было есть ли что-то вроде sed'а, но без регэкспов, чтобы не экранировать.

arturpub ★★
() автор топика
Ответ на: комментарий от arturpub

Даёшь отдельную утилиту для каждого самого редкого и ненужного юзкейса.

anonymous
()

Я не понял зачем в перле делать ещё одну копию интерпретатора, чтобы отредактировать файл. Это можно сделать в текущем процессе, написав функцию в несколько строчек. \Q и \E корректно работают с интерполируемыми переменными, если, конечно, они интерполируется тем же процессом, что создаёт регулярное выражение. То есть,

$ perl -le '$x = "\\E.\\Q"; print qr/\Q$x\E/'
(?^:\\E\.\\Q)
$ x="\\E.\\Q"
$ perl -le "print qr/\\Q$x\\E/"
(?^:.)

Если уж приспичило использовать qx||, то вот вариант решения:

qx|perl -np -i'*.bak' -e 'BEGIN{ \$filename = shift }; s/\\Q [\$filename]\\E// if \$.==$lineno;' '$filename' '$infofile'|;

anonymous
()
Ответ на: комментарий от anonymous

сделать в текущем процессе, написав функцию в несколько строчек

-i'*.bak' переизобретать не хочется.

Идея с шифтом интересная, но все равно ведь придется $filename шелэскейпить. Про \Q\E я только потом допер что это часть интерполяции, а не самого регэкспа.

arturpub ★★
() автор топика

Надо в указанном файле:строчке выкинуть

Есть такая проблема - обыная замена через одно место. Даже в пакете мускуля вроде была утили replace для этой цели.

Экранировать регулярки - да с GNU ERE - по-моему гиблое дело. Можно расчехлить flex, или вот такой ужас (ruby / perl было бы в разы проще):

awk -v fname=$l 'i = index($0,"["fname"]") {$0 = substr($0,1,i-1) substr($0,i+length(fname)+2)} 1'

Нормального unix-решения не знаю.

anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.