如何使用sed正确执行此修改或插入行?
我在一个测试crontab文件上运行此命令,其中包含以下内容:如何使用sed正确执行此修改或插入行?,sed,Sed,我在一个测试crontab文件上运行此命令,其中包含以下内容: 00 01 * * * foo --file example/example.xml --bla 00 02 * * * foo --file abc/abc.xml --bla 我正在尝试用其他内容替换第一行(如果存在),例如“bar”,或者如果它根本找不到它,则插入bar行,方法是运行以下命令: sed -e '@\(.*file example/example.xml .*\)@bar@' -e t -e 's@^@bar@
00 01 * * * foo --file example/example.xml --bla
00 02 * * * foo --file abc/abc.xml --bla
我正在尝试用其他内容替换第一行(如果存在),例如“bar”,或者如果它根本找不到它,则插入bar行,方法是运行以下命令:
sed -e '@\(.*file example/example.xml .*\)@bar@' -e t -e 's@^@bar@' file
我希望上面的代码尝试用bar替换匹配的示例行,如果找不到,则插入bar行。但是,当我使用上面的代码运行它时,我得到以下输出:
bar
bar00 02 * * * foo --file abc/abc.xml --bla
因此,它执行了替换,但不知何故,t
跳转到末尾没有发生,它还在下一行插入了bar
。出了什么问题
下面sat给出的命令似乎有效,但如果我运行两次,就无法追加,我不确定原因:
cat file
1 bin/appple #apple
2 bin/orange #orange
cat file | sed -e '\@.* #apple@{d}; $a 1 bin/apple #apple'
2 bin/orange #orange
1 bin/apple #apple
cat file | sed -e '\@.* #apple@{d}; $a 1 bin/apple #apple' | sed -e '\@.* #apple@{d}; $a 1 bin/apple #apple'
2 bin/orange #orange
前面两次,上面的命令都是我想要的,但最后一个命令只是删除了该行,而没有将其追加回去。为什么会这样?(顺便说一句,我把#改为\@是因为我用了#在那里,你可以想象它是一个crontab注释)你可以试试这个
sed
sed '\#file example/example.xml#{d}; $a bar' yourfile
修复打字错误(缺少的s
)后,命令:
sed -e 's@\(.*file example/example.xml .*\)@bar@' -e t -e 's@^@bar@' file
正在按照您的要求工作;我认为你误解了t
的范围。该测试依次应用于每一行输入,而不是整个脚本。剧本上说:
- 如果该行包含
,请将其替换为文件example/example.xml
条
- 如果替换完成,请跳到脚本的末尾(对于当前输入行)
- 将行的开头替换为
(第二个数据行会发生这种情况,因为它与条
不匹配)文件example/example.xml
条形时,不需要\(
和\)
,但这可能只是使用\1
的更复杂替换的残余)
嗯,;这就是为什么脚本的行为如此。我们怎样才能让它按你想要的方式运行?在某种程度上,答案取决于输出中行的顺序是否至关重要
如果顺序不重要,那么由by来完成工作。如果找到匹配的文本行,则删除该行。在文件末尾添加新行。因此,无论行是否在那里,输出都会在文件末尾包含新的必需输出。(对于crontab
文件,这应该足够了。)
如果顺序真的很重要,你的工作就要困难得多。在这种情况下,您可以利用保持空间来确定是否找到了模式。但是,如果您需要为其他内容保留空间,或者您需要替换或添加多个模式,那么您无法轻松地调整此模式以解决问题(您必须更加聪明)
如果命令重要的话
如果行的顺序不重要,不要使用此选项
示例:文件sed.script
包含:
/.*file example\/example.xml.*/ {
h
s//bar/
}
$ {
p
x
s/./X/
t end
s/.*/bar/
q
:end
d
}
此脚本有两组操作。第一组,当行与文件example/example.xml
匹配时是简单的;它将该行复制到保留空间(因此保留空间不再为空),然后执行替换操作
第二组要复杂得多;它在脚本末尾运行。首先,它打印当前行。如果第一个块修复了该行(因此,文件example/example.xml
出现在最后一行),它将打印该行的修改形式。然后它交换保持空间和模式空间。它进行了一次试替换(s//X/
)。如果进行了替换,则t
命令将跳转到标签end
,这意味着该行不是空的,这意味着保留空间已填充,因此该图案在替换之前(至少)被替换一次。如果t
没有跳转,则看不到匹配模式,因此代码将用bar
(替换文本)替换当前行并退出(打印最后一行并放弃脚本)。标签end
后面紧跟着d
,它删除当前行并“移动到下一个周期”,除非当$
匹配生效时没有下一个周期,因此没有任何内容可打印
示例运行:
$ cat file
00 01 * * * foo --file example/example.xml --bla
00 02 * * * foo --file abc/abc.xml --bla
$ sed -f sed.script file
bar
00 02 * * * foo --file abc/abc.xml --bla
$ sed -f sed.script file | sed -f sed.script
bar
00 02 * * * foo --file abc/abc.xml --bla
bar
$ sed -f sed.script /dev/null
$
第一个sed
显示example/example.xml
行被原位替换。第二个sed
显示当缺少example/example.xml
行时,会在末尾添加bar
。最后一个示例(/dev/null
)显示,您至少需要一行输入,它才能正常工作;它不会从空文件引导
可能有一种更简单的方法来处理这个问题。我只是还没弄清楚是什么
如果顺序不重要的话
这基本上是操作顺序颠倒的结果。当要删除的行是文件中的最后一行时,该选项起作用:
sed -e '$a bar' -e '/.*file example\/example.xml.*/d' file
这是干什么用的?一美元?这是在做什么?#
是一个模式匹配分隔符,$
是文件的结尾,是一个
是附加。我想你应该解释一下你在做什么。它是有效的,但不清楚它是如何工作的或为什么工作的,因为您已经重写了算法(它没有完全按照要求执行,但结果是等效的)您使用的是sed
的一个比较模糊的部分,带有\\\\
符号。正如您所指出的,它的行为与预期的一样,但当我运行两次时,它实际上执行的是删除,而不是追加。出于某些原因,您可以通过使用sed-e'$a bar'-e'/.*文件示例\/example.xml.*/d'
(简单地反转追加和删除操作)。第二个示例非常复杂,由于某种原因,@sat-give的简单命令在迭代两次时不起作用-正如我在上面的示例中所做的编辑一样。当最后一行匹配时,变量by可能会失败,因为d
终止当前代码