Простой поиск и замена без регулярных выражений - PullRequest
19 голосов
/ 01 ноября 2011

У меня есть файл с различными подстановочными знаками, который я хочу заменить из сценария оболочки (bash). У меня есть следующее, которое прекрасно работает, пока одна из переменных не содержит символов, которые являются специальными для регулярных выражений:

VERSION="1.0"
perl -i -pe "s/VERSION/${VERSION}/g" txtfile.txt   # no problems here

APP_NAME="../../path/to/myapp"
perl -i -pe "s/APP_NAME/${APP_NAME}/g" txtfile.txt  # Error!

Так что вместо этого я хочу что-то, что просто выполняет буквальную замену текста, а не регулярное выражение. Есть ли какие-нибудь простые однострочные вызовы с perl или другим инструментом, который сделает это?

Ответы [ 7 ]

18 голосов
/ 03 ноября 2011

«Правильный» способ сделать это - экранировать содержимое переменных оболочки, чтобы они не рассматривались как специальные символы регулярного выражения.Вы можете сделать это в Perl с помощью \ Q, как в

s/APP_NAME/\Q${APP_NAME}/g

, но при вызове из сценария оболочки обратный слеш должен быть удвоен, чтобы избежать его потери, например

perl -i -pe "s/APP_NAME/\\Q${APP_NAME}/g" txtfile.txt

Но я полагаю, что было бы гораздо проще написать весь скрипт на Perl

7 голосов
/ 01 ноября 2011

Как насчет следующего:

perl -i -pe "s|APP_NAME|\\Q${APP_NAME}|g" txtfile.txt

Поскольку вертикальная черта не является допустимым символом как часть пути, вы можете идти.

3 голосов
/ 02 ноября 2011

Вам не нужно использовать регулярное выражение для этого:

perl -pe '
  foreach $var ("VERSION", "APP_NAME") {
    while (($i = index($_, $var)) != -1) {
      substr($_, $i, length($var)) = $ENV{$var};
    }
  }
'

Убедитесь, что вы export свои переменные.

2 голосов
/ 13 сентября 2013

Мне не очень нравится этот ответ, потому что должен быть лучший способ сделать буквальную замену в perl.\Q загадочно.Использование quotemeta добавляет дополнительные строки кода.

Но ... Вы можете использовать substr для замены части строки.

#!/usr/bin/perl
my $name = "Jess.*";
my $sentence = "Hi, my name is Jess.*, dude.\n";
my $new_name = "Prince//";
my $name_idx = index $sentence, $name;
if ($name_idx >= 0) {
    substr ($sentence, $name_idx, length($name), $new_name ); 
}
print $sentence;

Вывод:

Hi, my name is Prince//, dude.
1 голос
/ 01 ноября 2011

Вы можете использовать регулярное выражение, но избегать любых специальных символов.

Нечто подобное может работать.

APP_NAME="../../path/to/myapp"
APP_NAME=`echo "$APP_NAME" | sed -e '{s:/:\/:}'`
perl -i -pe "s/APP_NAME/${APP_NAME}/g" txtfile.txt
1 голос
/ 01 ноября 2011

 perl -i -pe "s/APP_NAME/\Q${APP_NAME}\E/g" txtfile.txt

По какой-то причине это не совсем так, как рекламируется Этот вариант, кажется, работает, хотя:

 perl -i -pe "\$r = qq/\Q${APP_NAME}\E/; s/APP_NAME/\$r/go"

Обоснование: http://perldoc.perl.org/perlre.html#Escape-sequences

0 голосов
/ 06 ноября 2017

Мне удалось получить рабочее решение, частично основанное на кусочках ответов других людей:

app_name='../../path/to/myapp'
perl -pe "\$r = q/${app_name//\//\\/}/; s/APP_NAME/\$r/g" <<<'APP_NAME'

Это создает переменную perl $r из результата расширения параметра оболочки:

${app_name//\//\\/}

${            # open parameter expansion
app_name      # variable name 
//            # start global substitution
\/            # match / (backslash-escaped to avoid being interpreted as delimiter)
/             # delimiter
\\/           # replace with \/ (literal backslash needs to be escaped)
}             # close parameter expansion

Вся эта работа необходима для предотвращения того, чтобы косые черты внутри переменной обрабатывались как синтаксис perl, что в противном случае закрыло бы кавычки q// вокруг строки.

В заменяющей части используйте переменную $r ($ экранирован, чтобы не рассматривать его как переменную оболочки в двойных кавычках).

Тестирование:

$ app_name='../../path/to/myapp'
$ perl -pe "\$r = q/${app_name//\//\\/}/; s/APP_NAME/\$r/g" <<<'APP_NAME'
../../path/to/myapp
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...