【问题标题】:Use sed to escape a pattern to another sed使用 sed 将模式转义到另一个 sed
【发布时间】:2018-11-04 02:44:21
【问题描述】:

我想要一种使用 sed 命令进行替换的方法,该命令转义要在另一个 sed 命令中使用的“模式”(字符串)。 此转义过程必须包括对多行字符串模式的处理。

为了说明,我提供了下面的代码。它工作得很好(到目前为止测试良好),但是当我们有多行字符串时会失败(参见“STRING_TO_ESCAPE”)。

#!/bin/bash

# Escape TARGET_STRING.
read -r -d '' STRING_TO_ESCAPE <<'HEREDOC'
    $N = "magic_quotes_gpc = <b>"._("On")."</b>";
    $D = _("Increase your server security by setting magic_quotes_gpc to 'on'. PHP will escape all quotes in strings in this case."); 
    $S = _("Search for 'magic_quotes_gpc' in your php.ini and set it to 'On'."); 
    $R = ini_get('magic_quotes_gpc'); 
    $M = TRUE;
    $this->config_checks[] = array("NAME" => $N , "DESC" => $D , "RESULT" => $R , "SOLUTION" => $S , "MUST" => $M );
HEREDOC
ESCAPED_STRING=$(echo "'${STRING_TO_ESCAPE}'" | sed 's/[]\/$*.^|[]/\\&/g')
ESCAPED_STRING=${ESCAPED_STRING%?}
TARGET_STRING=${ESCAPED_STRING#?}

# NOTE: The single quotes in "'${STRING_TO_ESCAPE}'" serve to prevent spaces 
# being "lost" at the beginning and end of the string! The manipulations with 
# "ESCAPED_STRING" are used to remove them. When we use sed with the file being 
# input (flag "-i") this problem does not occur.

# Escape REPLACE_STRING.
read -r -d '' STRING_TO_ESCAPE <<'HEREDOC'
    /* NOTE: "Magic_quotes_gpc" is no longer required. We taught GOsa2 to deal with it (see /usr/share/gosa/html/main.php). By Questor */
    /* Automatic quoting must be turned on */
    /* $N = "magic_quotes_gpc = <b>"._("On")."</b>";
    $D = _("Increase your server security by setting magic_quotes_gpc to 'on'. PHP will escape all quotes in strings in this case."); 
    $S = _("Search for 'magic_quotes_gpc' in your php.ini and set it to 'On'."); 
    $R = ini_get('magic_quotes_gpc'); 
    $M = TRUE;
    $this->config_checks[] = array("NAME" => $N , "DESC" => $D , "RESULT" => $R , "SOLUTION" => $S , "MUST" => $M ); */
HEREDOC
ESCAPED_STRING=$(echo "'${STRING_TO_ESCAPE}'" | sed 's/[]\/$*.^|[]/\\&/g')
ESCAPED_STRING=${ESCAPED_STRING%?}
REPLACE_STRING=${ESCAPED_STRING#?}

# Do the replace.
STRING_TO_MODIFY=$(cat file_name.txt)
MODIFIED_STRING=$(echo "'${STRING_TO_MODIFY}'" | sed 's/$TARGET_STRING/$REPLACE_STRING/g')
MODIFIED_STRING=${MODIFIED_STRING%?}
MODIFIED_STRING=${MODIFIED_STRING#?}

echo "$MODIFIED_STRING"

谢谢! =D

【问题讨论】:

  • 这看起来使用patch 而不是sed 要容易得多。
  • 我不确定我是否遵循您想要完成的目标。 如何在第二个sed 命令中使用转义字符串?你是说你想要一种方法来检测与原始字符串的文字匹配吗?
  • @John Bollinger 我会尽量澄清。我想要的是能够在 sed 的路径中使用最初具有多行的字符串。我想要的是一个 pathern sed,它用多行转义这个字符串,以便在另一个 sed 中使用。示例:ESCAPED_STRING=$(echo "'${STRING_TO_ESCAPE}'" | sed 's/[]\/$*.^|[]/\\&amp;/g')
  • 是的,@EduardoLucio,我已经在您的示例代码中看到了这一点。据我所知,这似乎是您现在用来执行转义的基于sed 的机制。我在问你想如何使用它的 result,或者我们可能建议的任何替代方案。正如我已经写的答案所描述的那样,我怀疑您的问题根本不在于转义,而在于您正在使用结果的 sed 程序。
  • 这个问题似乎很难理解。请提供示例输入和所需的输出。

标签: bash shell sed sh


【解决方案1】:

此转义过程必须包括对多行字符串模式的处理。

我认为你找错树了。如果您尝试匹配多行模式,那么最重要的问题不是如何转义该模式,而是如何编写能够成功匹配任何内容的 sed 脚本。

问题是sed 一次读取一行输入。有多种方法可以收集多行并对此类集合进行操作,但您需要在程序中明确执行此操作。因此,sed 是尝试匹配任意多行文本的糟糕选择。为了使您的任务可行,您会想知道该模式将包含多少行,以便编写您的 sed 程序来专门针对它。即便如此,这对 Perl 来说可能是一个更好的工作。

更新:

因为我喜欢sed,但是,这里有一个示例,说明如何编写匹配多行模式的sed 程序:

#!/bin/sed -f
# Build up a three-line window in the pattern space
:a
/\(.*\
\)\{2\}/! { N; ba; }

# A(nother) multiline pattern.  If the pattern fails to match then the
# first line of the pattern space is printed and deleted, then
# we loop back to reload.
/^The\
quick\
brown$/! { P; D; ba; }

# Do whatever we want to do in the event of a match
s/brown/red/

# If control reaches here then the whole pattern space is printed,
# and if any input lines remain then we start again from the beginning
# with an initially-empty pattern space.

示例输入:

$ ./ml.sed <<EOF
The
quick
brown
fox          
jumped over
the lazy dog.
EOF

输出:

The
quick
red
fox
jumped over
the lazy dog.

请注意,换行符与普通字符匹配,但出于句法原因,模式或替换文本中的文字换行符需要以正常方式转义。

更新 2:

这是替换三行序列外观的变体

brown
fox          
jumped over

三行序

red
pig          
is fat

。当然,还有很多其他方法可以使用 sed 完成同样的事情,对于您的特定目的,其他方法之一可能比这更可取。

#!/bin/sed -f
:a
/\(.*\
\)\{2\}/! { N; ba; }

/^brown\
fox\
jumped over$/! { P; D; ba; }

s/.*/red\
pig\
is fat/

【讨论】:

  • “即便如此,这对 Perl 来说可能是一个更好的工作。” -> 优秀的答案!然后您可以使用 perl(或 awk)提供一个示例,因为如果没有转义,那么我们应该考虑另一种选择。如有必要,我可以更新问题。谢谢!
  • @EduardoLucio,示例中有 两个 多行模式,一个跨越物理行 4-5 的两行模式(但由于量词而匹配三行分组内),以及跨越物理线 10-12 的三线模式。后者一次匹配输入的前三行。然后只更改其中一行,但可以采取任何任意的sed 操作,例如用完全不同的东西替换它们。
  • 该示例演示的关键不是多行模式本身,而是一种将多行同时放入模式空间的方法,以便能够成功匹配多行- 线模式。
  • 是的,@EduardoLucio,可以修改示例以执行您所描述的操作。同样,最基本的一点是 sed 只有在其模式空间中同时有多个输入行时才能一次匹配多个输入行,如果您必须在您的 sed 程序中明确提供想要它。如果您要这样做,那么我强烈建议您学习sed 手册,因为我认为您不会通过剪切/粘贴/修改示例中的点点滴滴来轻松实现您的特定预期结果。跨度>
  • 很好,@EduardoLucio,我在现有示例的基础上添加了一个变体,用于执行您请求的替代替换。
猜你喜欢
  • 1970-01-01
  • 2021-12-10
  • 2015-01-17
  • 1970-01-01
  • 1970-01-01
  • 2020-05-14
  • 1970-01-01
  • 2015-05-30
  • 1970-01-01
相关资源
最近更新 更多