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

Posted

技术标签:

【中文标题】使用shell脚本在指定模式后将多行插入文件【英文标题】:Insert multiple lines into a file after specified pattern using shell script 【发布时间】:2014-04-25 04:32:42 【问题描述】:

我想使用 shell 脚本在一个文件中插入多行。 让我们考虑一下我的输入文件内容是: input.txt:

abcd
accd
cdef
line
web

现在我必须在 input.txt 文件中的“cdef”行之后插入四行。 插入我的文件后应该是这样的:

abcd
accd
cdef
line1
line2
line3
line4
line
web

我应该使用 shell 脚本进行上述插入。谁能帮帮我?

【问题讨论】:

【参考方案1】:

另一个sed

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

输入.txt:

abcd
accd
cdef
line
web

添加.txt:

line1
line2
line3
line4

测试:

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

如果您想应用 input.txt 文件中的更改。然后,使用-ised

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

如果您想使用正则表达式作为表达式,您必须使用带有sed-E 标签。

sed -E '/RegexPattern/r add.txt' input.txt

【讨论】:

有没有办法反其道而行之(从 input.txt 中删除 add.txt 中的文本)? 允许匿名文件的一种变体是将此处的文档通过管道传输到 sed 调用中,并使用r 命令从/dev/stdin 中读取。 嗨,有没有一种快速的方法可以在 add.txt 的添加行之前添加 4 个空格?【参考方案2】:

使用 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

【讨论】:

我是sed 的新手,但哇,我爱上了它的强大功能!如果你想追加一个空的换行符first,你必须像这样在追加命令之后转义反斜杠字符:sed "/cdef/a\\\nline1\nline2\nline3\nline4" input.txt。我不确定它为什么会这样,如果有人能解释一下就好了! 当前命令在每次提到cdef 时插入行*,有没有办法让它只在第一次遇到cdef 时插入,不再插入?跨度> MacOS sed 没有实现与 GNU sed 完全相同的 a 命令,因此上述方法在没有 mods 的 MacOS 中不起作用 - 至少从 macOS 10.13 开始(请参阅unix.stackexchange.com/a/131940/230763)【参考方案3】:
sed '/^cdef$/r'<(
    echo "line1"
    echo "line2"
    echo "line3"
    echo "line4"
) -i -- input.txt

【讨论】:

错过了这个好答案。 sed '/^cdef$/r' &lt;(printf "%s\n" line1..4) -i -- input.txt 更短但可读性更差。 请注意,当您从主机发出命令时,这在容器中不起作用,因为来自&lt;(...) 的文件描述符将在主机而不是客户机上创建。使用/someline/a&lt;added\ncontent&gt; 方法效果更好,特别是如果您执行sed "/someline/a$(echo 'here you can have newlines' | tr \\n @ | sed '\''s/@/\\n/g'\')" -i -- input.txt 之类的操作(不是完整示例且未经过适当测试,我现在没有时间,但这应该包括您需要的构建块) .【参考方案4】:

使用awk

awk '/cdef/print $0 RS "line1" RS "line2" RS "line3" RS "line4";next1' input.txt 

说明:

您使用/.../ 找到要插入的行 您使用print $0 打印当前行 RS 是内置的awk 变量,默认设置为new-line。 您添加由该变量分隔的新行 1 最后导致每隔一行打印。在它之前使用next 可以让我们阻止当前行,因为您已经使用print $0 打印了它。

$ awk '/cdef/print $0 RS "line1" RS "line2" RS "line3" RS "line4";next1' input.txt
abcd
accd
cdef
line1
line2
line3
line4
line
web

要更改文件,您可以:

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

【讨论】:

【参考方案5】:

这是一个基于@rindeal solution 的更通用的解决方案,它不适用于 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

【讨论】:

【参考方案6】:

这个答案很容易理解

在模式前复制 添加你的台词 在模式之后复制

替换原文件

FILENAME='app/Providers/AuthServiceProvider.php'

STEP 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

第 3 步添加文件的其余部分

grep -A 9999 'THEPATTERNYOUARELOOKINGFOR' $FILENAME >>$FILENAME_temp

替换原文件

mv $FILENAME_temp $FILENAME

如果您需要变量,请在第 2 步中将“EOL”替换为 EOL

cat << EOL >> $FILENAME_temp

this variable will expand: $variable1

EOL

【讨论】:

没必要尖叫

【参考方案7】:

我需要用最少的工具来模板化一些文件,对我来说,上面 sed -e '/../r file.txt 的问题是它只在打印出匹配的其余部分后附加文件,而不是替换它。

这不行(所有匹配都被替换,模式匹配从同一点继续)

#!/bin/bash

TEMPDIR=$(mktemp -d "$TMPDIR:-/tmp/$(basename $0).XXXXXXXXXXXX")
# remove on exit
trap "rm -rf $TEMPDIR" EXIT

DCTEMPLATE=$TEMPDIR/dctemplate.txt
DCTEMPFILE=$TEMPDIR/dctempfile.txt

# template that will replace
printf "0replacement
1$SHELL data
2anotherlinenoEOL" > $DCTEMPLATE

# test data
echo -e "xxy \n987 \nxx xx\n yz yxxyy" > $DCTEMPFILE

# print original for debug
echo "---8<--- $DCTEMPFILE"
cat $DCTEMPFILE
echo "---8<--- $DCTEMPLATE"
cat $DCTEMPLATE
echo "---8<---"

# replace 'xx' -> contents of $DCTEMPFILE
perl -e "our \$fname = '$DCTEMPLATE';" -pe 's/xx/`cat $fname`/eg' $DCTEMPFILE

【讨论】:

【参考方案8】:

您可以使用awkinput.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" line1..4) input.txt

【讨论】:

【参考方案9】:

如果您想使用 bash 脚本来执行此操作,这很有用。

echo $password | echo 'net.ipv4.ping_group_range=0 2147483647' |  sudo -S tee -a /etc/sysctl.conf

【讨论】:

您能否为您的命令添加一些解释,以帮助未来的读者了解所做的工作?【参考方案10】:

假设您有一个名为“insert.txt”的文件,其中包含您要添加的行:

line1
line2
line3
line4

如果 PATTERN 'cdef' 在您的 input.txt 文件中重复多次,并且您想在所有出现的模式 'cdef' 之后添加来自 'insert.txt' 的行,那么一个简单的解决方案是:

sed -i -e '/cdef/r insert.txt' input.txt

但是,如果 PATTERN 'cdef' 在您的 input.txt 文件中重复多次,并且您只想在模式第一次出现后添加来自 'insert.txt' 的行,那么一个漂亮的解决方案是:

printf "%s\n" "/cdef/r insert.txt" w | ed -s input.txt

如果模式在您的 input.txt 文件中只出现一次,这两种解决方案都可以正常工作。

【讨论】:

以上是关于使用shell脚本在指定模式后将多行插入文件的主要内容,如果未能解决你的问题,请参考以下文章

ubuntu怎么保存shell脚本文件

shell 脚本 EOF配合将cat将文本追加到指定文件

Shell脚本交互之:自动输入密码

linux_shell 编程学习-初识she'll

使用 grep 和 sed 在 shell 中查找和替换同一文件中的多行

Shell脚本自动输入密码的三种方式