我正在创建将使用 /bin/sh 或 /bin/bash 脚本执行的可执行文件,
我有一个文件,其中包含这样的结构,配置文件中只有一个#start
和#end
标记,我想替换之间的文本那些标签,
...
#start
FirewallRuleSet global {
FirewallRule allow tcp to google.com
FirewallRule allow tcp to facebook.com
#more rules
}
#end
FirewallRuleSet known-users {
FirewallRule allow to 0.0.0.0/0
}
...
期望的输出将是,
...
#start
FirewallRuleSet global {
FirewallRule allow tcp to google.com
FirewallRule deny tcp to facebook.com
FirewallRule deny tcp to twitter.com
FirewallRule allow tcp to exaple.com
#more rules
}
#end
FirewallRuleSet known-users {
FirewallRule allow to 0.0.0.0/0
}
...
如何用一些新文本替换#start
之间的整个文本?#end
我只想从此配置文件中添加或删除规则。
这是配置文件的一部分,我想修改该文本中允许的 url。
答案1
使用
sed '/#start/,/#end/替换命令'
例如,如果文件名为myconfig
,并且您想在该部分中将“allow”替换为“deny”,您可以说
sed '/#start/,/#end/s/allow/deny/' myconfig
这将使文件保持不变,并在标准输出上显示修改后文件的外观。您可能应该首先这样做,以验证您的命令是否正确。如果您想实际更改文件,请添加-i
选项:
sed -i '/#start/,/#end/s/allow/deny/' myconfig
如果您想更换所有的文本 (全部文本)在这两行之间,你可以做一些比卢卡斯的回答:
sed '/#start/,/#end/c\ 新文本行 1\ 新文本行 2\ ︙\ 新文本行n-1\ 新文本行n(最后)' ←关闭报价;这里没有反斜杠
c
是个Csed
(and ed
)中的hange 命令;它的意思是“替换整行”。你不能简单地让#start
和#end
线保持不变。如果您想保留它们,则必须重新插入它们:
sed -i '/#start/,/#end/c\
#start\
FirewallRuleSet global {\
FirewallRule allow tcp to google.com\
FirewallRule deny tcp to facebook.com\
︙ \
\
#more rules\
}\
#end' myconfig
/#start/,/#end/
指定范围 — 从包含 的第一行#start
到包含 的第一行#end
。如果您需要查找包含这些字符串而不包含其他内容的行,请使用/^#start$/,/^#end$/
.
答案2
基于G-Man的回答和评论:
sed -i '/#start/,/#end/ {
//!d
/#start/a\
some new text\
more lines\
end of new text (no backslash here!)
}' myconfig
解释:
/#start/,/#end/ { .... }
对文本“#start”和“#end”(含)之间的每一行执行大括号中的命令。比较一下G-Man的答案。a
是附加命令。它仅在匹配“#start”的行上执行,以便添加新文本。它将追加行,直到不以反斜杠+换行符终止的行。
答案3
因为你有两种状态,即两条不同行的存在在这之间移动,这是 awk(或 perl 或 python)的工作。由于我当前的语言是 python,程序将如下所示:
import sys
rule_file = sys.argv[1]
new_rules = sys.argv[2]
mode = "save_rules"
for line in open(rule_file):
line = line.strip()
if line == "#start":
print line
print new_rules
mode = "replace_rules"
elif line == "#end":
mode = "save_rules"
print line
elif mode == "save_rules":
print line
现在将其保存到rule_replace.py并调用它
python rule_replace.py my_rule_file.txt 'FirewallRuleSet global {
FirewallRule allow tcp to google.com
FirewallRule deny tcp to facebook.com
FirewallRule deny tcp to twitter.com
FirewallRule allow tcp to exaple.com
#more rules
}' >new_rules.txt
当然,您不必将新规则放在命令行上,我假设您将它们放在 shell 变量中,然后调用将如下所示:
$ python rule_replace.py my_rule_file.txt $new_rules
请注意,此脚本虽然有效,但并不是生产中某些内容的解决方案。它不会捕获任何错误(例如,如果源文件不存在)。它假设不检查 #start 行后面总是跟着 #end 行,并且这些行与您所描述的完全相同。如果投入生产,它还可以使用一些日志记录。
答案4
根据 G-Man 的答案,以下是如何执行此操作并使用自定义分隔符和变量替换(由于复杂性,这并不是立即显而易见的)
给定 inputfile.txt:
Line1
Line2
<!-- /START_MARKER/ -->
Line4
Line5
Line6
<!-- /END_MARKER/ -->
Line8
Line9
使用这些命令/脚本:
customtext="Any kind of variable text here"
sed -i '\%<!-- /START_MARKER/ -->%,\%<!-- /END_MARKER/ -->%c\
foo '"$customtext"' abcxyz whatever' inputfile.txt
结果是:
Line1
Line2
Any kind of variable text here
Line8
Line9
这里发生了很多事情,解释如下:
'
- 必须使用单引号来包裹所有内容
\%
- 使用自定义分隔符时(例如,如果/
您的标记必须使用不同的分隔符),则必须在此处对其进行转义
<!-- /START_MARKER/ -->
- 文字开始标记,在本例中,它是用于演示目的的怪异示例。
%
- sed 分隔符,未转义
,
- 逗号 (?)
\%
- 再次使用 sed 分隔符,这次必须转义
<!-- /END_MARKER/ -->
- 文字结束标记
%c
- sed 分隔符(未转义)和c
\
- 反斜杠,表示应使用以下文本/行作为替换
foo
- 一些替换文本
'"$customtext"'
- 自定义变量文本,注意使用'
然后"
启用变量替换,然后"
和'
返回自由文本模式
abcxyz whatever
- 一些额外的替换文本
'
- 结束单引号
inputfile.txt
- 文件名