使用shell脚本在指定模式之后将多行插入文件

97

我希望您能够使用Shell脚本将多行文本插入到文件中。 假设我的输入文件内容为: input.txt:

abcd
accd
cdef
line
web

现在我需要在文件中的" cdef "一行后面插入四行内容。插入后,我的文件应该像这样更改:

abcd
accd
cdef
line1
line2
line3
line4
line
web

我应该使用Shell脚本进行上述插入操作。有人可以帮我吗?

12个回答

125

另一个sed

sed '/cdef/r add.txt' input.txt

input.txt:

abcd
accd
cdef
line
web

add.txt:

line1
line2
line3
line4

测试:

sat:~# sed '/cdef/r add.txt' input.txt
abcd
accd
cdef
line1
line2
line3
line4
line
web

如果你想将更改应用于 input.txt 文件,则使用带有 sed-i

sed -i '/cdef/r add.txt' input.txt
如果您想将正则表达式用作表达式,则必须使用-E标记与sed一起使用。
sed -E '/RegexPattern/r add.txt' input.txt

1
有没有一种方法可以反过来做这件事(从input.txt中删除在add.txt中找到的文本)? - Sina
3
一种允许匿名文件的变体是将Here文档导入sed调用中,并使用“r”命令从/dev/stdin读取。 - potong
你好,有没有一种快速的方法在从 add.txt 添加的行前添加4个空格? - Hud
1
这种方法的问题在于,如果文件中有100个cdef出现,那么它也会将add.txt的内容粘贴到你的文件中100次 :( - RAM237

52

使用GNU sed

sed "/cdef/aline1\nline2\nline3\nline4" input.txt

如果您的起点是:

abcd
accd
cdef
line
web

这将产生:

abcd
accd
cdef
line1
line2
line3
line4
line
web

如果你想直接将更改保存在文件中,请使用以下命令:

sed -i "/cdef/aline1\nline2\nline3\nline4" input.txt

4
我对 sed 还不熟悉,但我真的很喜欢它的强大功能!如果你想先添加一个空白行,你需要在 append 命令之后转义反斜杠字符,像这样:sed "/cdef/a\\\nline1\nline2\nline3\nline4" input.txt。虽然我不确定为什么要这样做,但如果有人能解释一下就太好了! - hdl
2
当前命令在每次出现 cdef 时都插入该行*,有没有办法使其仅在第一次遇到 cdef 时插入,而不再插入? - CMCDragonkai
2
MacOS的sed没有像GNU sed一样精确实现a命令,所以上述内容在至少macOS 10.13中无法在MacOS中运行(参见https://unix.stackexchange.com/a/131940/230763) - Mike Lutz
MacOS的sed命令与GNU sed命令在处理-i选项时有所不同。在MacOS上,-i需要一个带有备份后缀的参数。您需要指定-i '' - Craig Buchek

31
sed '/^cdef$/r'<(
    echo "line1"
    echo "line2"
    echo "line3"
    echo "line4"
) -i -- input.txt

错过了这个好答案。更短但不易读的是 sed '/^cdef$/r' <(printf "%s\n" line{1..4}) -i -- input.txt - Walter A
2
请注意,如果您从主机发出命令,则此方法在容器中不起作用,因为<(...)的文件描述符将在主机上创建而不是客户机上。使用/someline/a<added\ncontent>方法更好,特别是如果您执行类似于sed "/someline/a$(echo 'here you can have newlines' | tr \\n @ | sed '\''s/@/\\n/g'\')" -i -- input.txt的操作(这不是一个完整的示例,也没有经过适当测试,我现在没有时间,但这应该包括您所需的构建块)。 - Luc

19

使用 awk:

awk '/cdef/{print $0 RS "line1" RS "line2" RS "line3" RS "line4";next}1' input.txt 
说明:

  • 使用 /.../ 找到要插入的行
  • 使用 print $0 打印当前行
  • RS 是内置的 awk 变量,默认设置为 new-line
  • 您可以通过此变量添加分隔的新行
  • 1 在末尾导致打印每个其他行。在它之前使用 next 可以防止当前行,因为您已经使用 print $0 打印了它。
$ awk '/cdef/{print $0 RS "line1" RS "line2" RS "line3" RS "line4";next}1' input.txt
abcd
accd
cdef
line1
line2
line3
line4
line
web

若要对文件进行更改,您可以执行以下操作:

awk '...' input.txt > tmp && mv tmp input.txt

8

这里是基于@rindeal 解决方案的更通用的解决方案,它在MacOS/BSD上不起作用(/r需要一个文件):

cat << DOC > input.txt
abc
cdef
line
DOC

$ cat << EOF | sed '/^cdef$/ r /dev/stdin' input.txt
line 1
line 2
EOF

# outputs:
abc
cdef
line 1
line 2
line

这可以用来将任何东西传输到给定位置的文件中:

$ date | sed '/^cdef$/ r /dev/stdin' input.txt

# outputs
abc
cdef
Tue Mar 17 10:50:15 CET 2020
line

此外,您可以添加多个命令以允许删除标记行 cdef

$ date | sed '/^cdef$/ {
  r /dev/stdin
  d
}' input.txt

# outputs
abc
Tue Mar 17 10:53:53 CET 2020
line

1
你可以使用 awk 将一些命令的输出插入到 input.txt 的中间。
要插入的行可以是 cat otherfilels -l 或由 printf 生成的带有数字的 4 行。
awk 'NR==FNR {a[NR]=$0;next}
    {print}
    /cdef/ {for (i=1; i <= length(a); i++) { print a[i] }}'
    <(printf "%s\n" line{1..4}) input.txt

0
假设您有一个名为'insert.txt'的文件,其中包含您想要添加的行:
line1
line2
line3
line4

如果在您的input.txt文件中PATTERN 'cdef'重复多次,并且您想要在所有出现模式'cdef'之后添加来自'insert.txt'的行,则一个简单的解决方案是: sed -i -e '/cdef/r insert.txt' input.txt 但是,如果在您的input.txt文件中PATTERN 'cdef'重复多次,并且您只想在第一次出现模式后添加来自'insert.txt'的行,则一个优美的解决方案是: printf "%s\n" "/cdef/r insert.txt" w | ed -s input.txt 如果该模式仅在您的input.txt文件中出现一次,则两种解决方案都可以正常工作。

0

基于 @rindeal 的 solution,但输入更易读

sed '/^cdef$/r'<(cat <<EOF
line1
line2
line3
line4
EOF
) -i -- input.txt

0
将内容放在第四行上(就像您想要的那样)
sed -i "4i line1\nline2\nline3\nline4" input.txt

如果您不想将更改就地保存到文件中,请删除“-i”:

sed "4i line1\nline2\nline3\nline4" input.txt

使用GNU的sed*

如果您从以下内容开始input.txt:

abcd
accd
cdef
line
web

这将产生:

abcd
accd
cdef
line1
line2
line3
line4
line
web

0

这个答案很容易理解

  • 在模式前面复制
  • 添加你自己的行
  • 在模式后面复制
  • 替换原始文件

    FILENAME='app/Providers/AuthServiceProvider.php'

步骤1 复制直到模式

sed '/THEPATTERNYOUARELOOKINGFOR/Q' $FILENAME >>${FILENAME}_temp

步骤2 添加您的代码行

cat << 'EOL' >> ${FILENAME}_temp

HERE YOU COPY AND
PASTE MULTIPLE
LINES, ALSO YOU CAN
//WRITE COMMENTS

AND NEW LINES
AND SPECIAL CHARS LIKE $THISONE

EOL

步骤三:添加文件的其余部分

grep -A 9999 'THEPATTERNYOUARELOOKINGFOR' $FILENAME >>${FILENAME}_temp

替换原始文件

mv ${FILENAME}_temp $FILENAME

如果你需要变量,在第二步中用 EOL 替换 'EOL'

cat << EOL >> ${FILENAME}_temp

this variable will expand: $variable1

EOL

3
没必要尖叫。 - Luc

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接