使用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
文件中的更改。然后,使用-i
和sed
。
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' <(printf "%s\n" line1..4) -i -- input.txt
更短但可读性更差。
请注意,当您从主机发出命令时,这在容器中不起作用,因为来自<(...)
的文件描述符将在主机而不是客户机上创建。使用/someline/a<added\ncontent>
方法效果更好,特别是如果您执行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】:您可以使用awk
在input.txt
中间插入某些命令的输出。
要插入的行可以是cat otherfile
、ls -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脚本在指定模式后将多行插入文件的主要内容,如果未能解决你的问题,请参考以下文章