简单搜索和替换没有正则表达式

时间:2011-11-01 18:00:20

标签: perl bash text

我有一个包含各种通配符的文件,我希望能够从(bash)shell脚本替换它。我有以下内容非常有效,直到其中一个变量包含对正则表达式特殊的字符:

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 个答案:

答案 0 :(得分:18)

执行此操作的“正确”方法是转义shell变量的内容,以便它们不会被视为特殊的正则表达式字符。您可以使用\ Q在Perl中执行此操作,如

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

但是当从shell脚本调用时,反斜杠必须加倍以避免丢失,如此

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

但我建议用Perl

编写整个脚本要容易得多

答案 1 :(得分:7)

以下内容如何:

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

由于垂直条不是合法角色作为路径的一部分,因此您可以继续使用。

答案 2 :(得分:3)

您不必使用正则表达式:

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

确保export变量。

答案 3 :(得分:2)

我不是特别喜欢这个答案,因为应该有更好的方法在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.

答案 4 :(得分:1)

<子> <击>

<击>
 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

答案 5 :(得分:1)

您可以使用正则表达式但转义任何特殊字符。

这样的事情可能有用。

APP_NAME="../../path/to/myapp"
APP_NAME=`echo "$APP_NAME" | sed -e '{s:/:\/:}'`
perl -i -pe "s/APP_NAME/${APP_NAME}/g" txtfile.txt

答案 6 :(得分:0)

我设法得到一个有效的解决方案,部分基于其他人的答案:

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

这将从shell参数扩展的结果中创建一个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$被转义,以防止它被视为双引号内的shell变量。

测试出来:

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