Ответ 1
Как насчет следующего:
perl -i -pe "s|APP_NAME|\\Q${APP_NAME}|g" txtfile.txt
Так как вертикальная полоса не является юридическим символом как часть пути, вам хорошо идти.
У меня есть файл с различными подстановочными знаками, которые я хочу заменить из оболочки bash script. У меня есть следующее, которое отлично работает, пока одна из переменных не содержит символов, специально предназначенных для регулярных выражений:
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 или другим инструментом, который это сделает?
Как насчет следующего:
perl -i -pe "s|APP_NAME|\\Q${APP_NAME}|g" txtfile.txt
Так как вертикальная полоса не является юридическим символом как часть пути, вам хорошо идти.
"Правильный" способ сделать это состоит в том, чтобы избежать содержимого переменных оболочки, чтобы они не воспринимались как специальные символы регулярных выражений. Вы можете сделать это в Perl с \Q, как в
s/APP_NAME/\Q${APP_NAME}/g
но при вызове из оболочки script обратная косая черта должна быть удвоена, чтобы избежать ее потери, например
perl -i -pe "s/APP_NAME/\\Q${APP_NAME}/g" txtfile.txt
Но я предлагаю, чтобы было намного проще написать весь script в Perl
Вам не нужно использовать регулярное выражение для этого:
perl -pe '
foreach $var ("VERSION", "APP_NAME") {
while (($i = index($_, $var)) != -1) {
substr($_, $i, length($var)) = $ENV{$var};
}
}
'
Убедитесь, что вы export
ваши переменные.
Мне не очень нравится этот ответ, потому что должен быть лучший способ сделать буквальную замену в 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.
<суб >
perl -i -pe "s/APP_NAME/\Q${APP_NAME}\E/g" txtfile.txt
Забастовкa > суб >
По какой-то причине это не совсем так, как рекламируется. Эта вариация, похоже, работает, хотя:
perl -i -pe "\$r = qq/\Q${APP_NAME}\E/; s/APP_NAME/\$r/go"
Обоснование: http://perldoc.perl.org/perlre.html#Escape-sequences
Вы можете использовать регулярное выражение, но избегать любых специальных символов.
Что-то вроде этого может работать.
APP_NAME="../../path/to/myapp"
APP_NAME=`echo "$APP_NAME" | sed -e '{s:/:\/:}'`
perl -i -pe "s/APP_NAME/${APP_NAME}/g" txtfile.txt
Мне удалось получить рабочее решение, частично основанное на кусочках и ответах других народов:
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