使用sed用多行替换一个单词?
Posted
技术标签:
【中文标题】使用sed用多行替换一个单词?【英文标题】:Replace a word with multiple lines using sed? 【发布时间】:2012-04-23 20:20:49 【问题描述】:我正在编写一个 bash 脚本,该脚本必须准备发送给用户的电子邮件。
它聚合了一些数据,最终形成多行数据。对于存储在$DATA
中的示例。
现在,经过一些 stfw,我发现了一些东西,例如 sed -ei "s/_data_/$DATA/g" mail.tpl
和 sed replace with variable with multiple lines。它们都不起作用。
现在的问题是,如何让sed
用多行文本替换某些内容?
(也欢迎sed
的替代品!)
【问题讨论】:
sed replace with variable with multiple lines的可能重复 @ZsoltBotykai 你不说? :D 我什至在我的问题中提到了它...... 顺便说一句,不要为您的私有 shell 变量使用大写。 @tripleee 为什么不呢? 因为这样可以避免与保留变量(大写)发生意外冲突。对于这确切的含义没有达成共识,但是您的脚本的私有变量绝对不是POSIX本条款中所预期的“系统变量”。见***.com/q/673055/874188 【参考方案1】:您可以使用 AWK 使用变量替换来做到这一点。我们可以使用-v
在AWK 中设置一个变量,然后使用AWK 的gsub
函数将所有出现的正则表达式替换为该变量。
例如,如果文件test
具有以下内容...
foo
bar
blah _data_and_data_
foo
_data_ foobar _data_ again
... 而 Bash 变量 $DATA
是...
1
2
3
4
5
...然后awk -v r=$DATA 'gsub(/_data_/,r)1' test
将文件test
中所有出现的正则表达式_data_
替换为$DATA
的内容,结果如下:
foo
bar
blah 1
2
3
4
5and1
2
3
4
5
foo
1
2
3
4
5 foobar 1
2
3
4
5 again
【讨论】:
天哪,这工作!我希望我能再为你 +1 几次,你救了我! 嘿肯特,这是一个旧的,但您似乎缺少 $DATA 周围的引号。确认? 确实应该添加引号:awk -v r="$DATA" 'gsub(/_data_/,r)1' test 显然有些 (?) awks 会不喜欢这个并说"newline in string"
(尽管DATA
周围没有双引号的答案会以不同的方式失败)。
对 awk-noobs 的简短解释会很好【参考方案2】:
如果您使用“\n
”构建多行文本,则可以使用简单的sed
命令:
DATA=`echo $DATA | tr '\n' "\\n"`
#now, DATA="line1\nline2\nline3"
sed "s/_data_/$DATA/" mail.tpl
【讨论】:
我从那个方法得到sed: -e expression #1, char 32: unterminated 's' command
。
这不是完全可移植的;并非所有sed
方言都接受\n
有向图来表示文字换行符。在其他一些方言中,您可能需要在文字换行符之前使用反斜杠。此页面上的其他答案会更详细地向您展示如何做到这一点。
再看这个,我认为tr
没有any 版本可以将一个字符替换为两个字符;这只是这项工作的错误工具。换行符意外丢失,因为您错误地没有引用echo
的参数,但这有多种其他不良副作用;而tr
在这里根本什么都不做。 这不应该是公认的答案。
是的对我也不起作用。试试this solution (below)
鉴于 shell 是 Bash,那么就不需要(损坏的)tr
调用 - just use $DATA//$'\n'/\\n
。【参考方案3】:
我试过sed 's/pattern/\na\nb\nc/g'
,但它不适用于所有系统。起作用的是在替换模式中添加\
,后跟换行符,如下所示:
sed 's/pattern/a\
b\
c/g'
当看到模式时,这会附加一行包含b
和一行包含c
。
要将其放入变量中,请使用双反斜杠:
export DATA="\\
a\\
b\\
c"
然后:
sed "s/pattern/$DATA/g"
注意双引号。
【讨论】:
【参考方案4】:您可以将数据放入临时文件并运行:
$ sed '/_data_/r DATA_FILE' mail.tpl | sed '/_data_/d'> temp; mv temp mail.tpl
【讨论】:
【参考方案5】:我建议简单地将 sed 替换为 perl 命令,如下所示:
perl -i.bak -pe 's/_data_/$ENV"DATA"/g' mail.tpl
【讨论】:
这是唯一对我有用的 OSX。所有其他基于 sed 和 awk 的方法对我来说都失败了。 如果DATA
包含斜杠,这将会以令人不安的方式失败。但是您可以export DATA
并以$ENV"DATA"
从Perl 内部访问它,而不会混淆代码和数据。所以's/_data_/$ENV"DATA"/g'
很简单。
@anubhava 和 @tripleee,你们拯救了我的一天。这是唯一对我有用的解决方案:sed
和 awk
都不能解决问题。谢谢。【参考方案6】:
戒指持有人的回答对我不起作用;我认为tr
的使用是错误的,它的编写方式只是通过使用echo
来去除换行符。
相反,我使用了sed
。我使用来自another answer 的代码来替换换行符(来源:Zsolt Botykai)。我还期望在我的输入中出现一些美元符号 ($
),所以我也处理了这一点。您可能需要添加其他输入处理。请注意在echo
中使用双引号来保留换行符。
DATA="$(cat whatever)"
ESCAPED_DATA="$(echo "$DATA" | sed ':a;N;$!ba;s/\n/\\n/g' | sed 's/\$/\\$/g')"
那么你可以在sed
中使用$ESCAPED_DATA
:
cat input | sed 's/one liner/'"$ESCAPED_DATA"'/' > output
只是想我会分享。
【讨论】:
当在带有$'\n'
构造的bash
脚本中构建了多行字符串时,这也很有效(当然,开头的cat
是不需要的,因为字符串已经在一个变量中)。【参考方案7】:
将变量回显到临时文本文件中。
将文本文件插入 mail.tpl 并从 mail.tpl 中删除 data
echo $DATA > temp.txt
sed -i -e "/_data_/r temp.txt" -e "//d" mail.tpl
【讨论】:
在尝试了许多其他解决方案之后,这是唯一一个对我有用的解决方案。【参考方案8】:不确定您是否尝试将“\n”放入替换部分
sed 's/[pattern]/\
[line 1]\n\
[line 2]\n\
[line n]\n\
/g' mail.tpl
出于可读性原因,第一行有 /\。之后的每一行都是一个独立的行,就像您在文本编辑器中找到的那样。最后一行是独立的,再次出于可读性原因。如果需要,您可以制作所有这一条线。当我测试它时,它可以在 Debian Jessie 上运行。
【讨论】:
这太sed了。:)【参考方案9】:用\
转义所有换行符(最后一个除外)对我有用。
最后一个换行符不得转义以免破坏s
命令。
例子:
DATA="a
b
c"
ESCAPED=$(echo "$DATA" | sed '$!s@$@\\@g')
echo "$ESCAPED"
a\
b\
c
sed "s/pattern/$ESCAPED/" file
【讨论】:
我必须使用双斜线。以上是关于使用sed用多行替换一个单词?的主要内容,如果未能解决你的问题,请参考以下文章