我正在尝试使用 sed 获取文件的内容并将其插入到另一个文件中的匹配模式之后。我的问题非常类似于这个问题,但我希望内联插入文件的内容而不是在新行上插入。我怎样才能做到这一点?
使用我引用的示例问题,第一个答案正是我想要的;但是,我希望插入发生内联:
sed '/First/r file1.txt' infile.txt
我想要插入的实际数据是一个 JSON 文件:
[
{
"foo": "bar",
"baz": "biff",
"data": [
{
"a": 1945619,
"b": [
{
"c": 512665,
"d": "futz"
}
]
}
]
}
]
答案1
在您链接的问题中已经有了很好的awk
答案,只需使用以下命令稍微修改一下printf
即可,而不是print
插入不带换行符的内容:
awk '/First/ { printf $0; getline < "File1.txt" }1' infile.txt
结果:
Some Text here
FirstThis is text to be inserted into the File.
Second
Some Text here
您可能需要在“First”之后添加空格或其他分隔符printf $0 " "; ...
如果插入的文件有很多行,则:
awk '/First/{printf $0; while(getline line<"File1.txt"){print line};next}1' infile.txt
结果:
Some Text here
First[
{
"foo": "bar",
"baz": "biff",
"data": [
{
"a": 1945619,
"b": [
{
"c": 512665,
"d": "futz"
}
]
}
]
}
]
Second
Some Text here
答案2
您可以使用perl
(获取文件内容并pattern
用pattern
+替换file content
):
perl -pe '$text=`cat insert.txt`; chomp($text); s/PAT/$&$text/' file.txt
添加-i
就地编辑;g
在每次 PAT(模式)出现后附加,例如:
perl -i -pe '$text=`cat insert.txt`; chomp($text); s/PAT/$&$text/g' file.txt
另一种方式,使用ed
:
printf '%s\n' /PAT/s/PAT/\&\\ \/ - kb ". r insert.txt" j \'b j ,p q | ed -s file.txt
要就地编辑,请替换,p
为w
:
printf '%s\n' /PAT/s/PAT/\&\\ \/ - kb ". r insert.txt" j \'b j w q | ed -s file.txt
可能没有人感兴趣这是如何工作的,但无论如何,printf
将命令列表传递给ed
:
/PAT/s/PAT/&\ # set address to first line matching PAT and
/ # split the line right after PAT
- # set address one line before (return to the line matching PAT)
kb # mark the current line
. r insert.txt # insert content of insert.txt after this line
j # join current line and the next
'b # set address to marked line (return to the line matching PAT)
j # join current line and the next one
,p # print file content
q # quit editor
或者,不使用printf
and |
:
ed -s file.txt <<< $'/PAT/s/PAT/&\\\n/\n-\nkb\n. r insert.txt\nj\n\'b\nj\nw\nq\n'
答案3
因此,要使这项工作可移植地工作会有点棘手sed
- 您应该寻找cut
和/或paste
使用一些正则表达式前体在该上下文中生成其脚本 - 这是因为sed
总是会插入一个\n
ewline前ead的输出r
。尽管如此,使用 GNU sed
:
sed '/First/{x;s/.*/cat file/e;H;x;s/\n//}' <<\IN
First
Second
Third
IN
每次遇到您的地址时都会e
执行此操作。它在旧空间中执行此操作cat
/First/
h
(无论如何 - 一个备用缓冲区 - 因为我改变x
了它们,它实际上发生在曾经是h
旧空间的模式空间中)以便保留行匹配的内容First
,然后将cat
的输出附加到您的行并删除中间的\n
ewline。
输出:
First[
{
"foo": "bar",
"baz": "biff",
"data": [
{
"a": 1945619,
"b": [
{
"c": 512665,
"d": "futz"
}
]
}
]
}
]
Second
Third
现在,如果您希望文件的全部内容适合之间一行的两个部分的工作方式必须略有不同,因为使用上面的命令我只需删除行之间的尾随换行符结尾匹配行的位置和文件的开头。不过,你也可以这样做:
sed '/First/{s//&\n/;h
s/.*/{ cat file; echo .; }/e;G
s/\(.*\).\n\(.*\)\n/\2\1/
}' <<\IN
Third
Second
First Second Third
Third
Second
First Second Third
IN
这会在匹配处用 ewline 字符分割行\n
,将其保存在h
旧空间中,e
xecutes cat
(用其输出替换模式空间)G
将保留空间的内容附加到另一个\n
ewline 字符后面的新模式空间,然后重新排列\n
行分隔符。
我确实echo .
保留了所有尾随的\n
ewline 字符file
- 但如果这不是你的愿望(无论如何与你的例子不太相关)您可以不使用它,并在下面的替换中删除.
前面的第一个。.\n
s///
在重新排列模式空间之前,它看起来像这样:
^cat's output - any number of newlines.*.\nmatch on First\nrest of match$
输出:
Third
Second
First[
{
"foo": "bar",
"baz": "biff",
"data": [
{
"a": 1945619,
"b": [
{
"c": 512665,
"d": "futz"
}
]
}
]
}
] Second Third
Third
Second
First[
{
"foo": "bar",
"baz": "biff",
"data": [
{
"a": 1945619,
"b": [
{
"c": 512665,
"d": "futz"
}
]
}
]
}
] Second Third