无需正则表达式即可简单搜索和替换

问题描述 投票:0回答:7

我有一个包含各种通配符的文件,我希望能够从(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 或其他工具的简单单行调用可以做到这一点?

perl bash text
7个回答
20
投票

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

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

但是当从 shell 脚本调用时,反斜杠必须加倍以避免丢失,就像这样

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

但我建议用 Perl 编写整个脚本会容易得多


11
投票

使用以下内容:

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

由于竖线不是路径中的合法字符,所以你可以开始了。


9
投票

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

5
投票

您不必为此使用正则表达式(使用 substr()index()length()):

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

确保您

export
您的变量。


2
投票

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

这样的东西可能会起作用。

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

2
投票

用途:

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

基本原理:转义序列

\Q          quote (disable) pattern metacharacters until \E
\E          end either case modification or quoted section, think vi

使用

qq/abc/
语法代替
"abc"
双引号字符串。


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
© www.soinside.com 2019 - 2024. All rights reserved.