如何使用bash sed 命令更改此字符串:
<Directory /var/www/>
Options Indexes FollowSymLinks
AllowOverride None
Require all granted
</Directory>
进入以下字符串? (仅更改字符串的第3行)
<Directory /var/www/>
Options Indexes FollowSymLinks
AllowOverride All
Require all granted
</Directory>
注1:我不只是要将字符串'AllowOverride None'作为目标,因为文件中还有其他一些不应更改的事件。我需要定位以<Directory /var/www>
注2:我还需要覆盖该文件。所以,在你的答案中考虑到这一点。并提供不同版本的GNU /非GNU版本的sed以防万一。
答案 0 :(得分:7)
由于模式包含斜杠,因此请使用\%
(对于任何字符%
)来标记搜索模式。然后使用:
sed -e '\%^<Directory /var/www/>%,\%^</Directory>% s/AllowOverride None/AllowOverride All/'
\%…%
内的搜索模式将搜索范围限制在匹配模式之间的行,{ s/…/…/; }
在该范围内查找所需的模式并进行适当的替换。
如果您不想将其限制为单个目录部分,而是限制所有目录部分,请相应地调整开始模式。例如,这将匹配任何<Directory>
部分:
sed -e '\%^<Directory [^>]*>%,\%^</Directory>% s/AllowOverride None/AllowOverride All/'
根据您的要求,您可以使其更具选择性。
答案 1 :(得分:3)
简单版本依赖&lt; Directory ...&gt; 之后的两行内的 AllowOverride 行并使用GNU sed扩展名,这是:< / p>
sed '/^<Directory/,+2 { s/AllowOverride None/AllowOverride All/g; }'
更新:这是不依赖于任何GNU扩展的版本(我先尝试过,但是输入了一个错字,并且感到惊讶的是它不起作用,这就是为什么首先发布其他版本的原因):
sed '/^<Directory/,/^<\/Directory>/ { s/AllowOverride None/AllowOverride All/; }'
答案 2 :(得分:1)
使用Gnu Sed:
sed -zie 's!\(<Directory /var/www/>[^<]*AllowOverride\) None!\1 All!' ex1.txt
-z
用于Null分隔记录:所有文件都是一条记录,
所以只需做一个简单的替换。[^<]*
(多行)正则表达式尊重目录边界,并允许灵活的格式和顺序。答案 3 :(得分:1)
你的问题很好地说明了口头禅,不要使用sed 。实际上,您不应该将任何正则表达式引擎用于像XML这样的无上下文语言。但你可以用 awk 来接近,也许足够接近。
#! /usr/bin/awk -f
/<Directory \/var\/www\/>/ {
line = NR
}
/ AllowOverride None/ && line + 2 == NR {
gsub( /None/, "All" )
}
{ print }
这样你就没有任何花哨的非标准正则表达式,并且你的代码确切地说明了它的意思:如果在“目录”行之后找到“AllowOverride”2行,则替换它。上面的正则表达式都非常简单(和Posix兼容),并且应该适用于任何版本的awk。
答案 4 :(得分:0)
user只有check here已经给出了答案。
一些参考
在最简单的sed调用中,它在模式空间中有一行文本,即。来自输入的1行\ n分隔文本。模式空间中的单行没有\ n ...这就是你的正则表达式找不到任何东西的原因。
你可以在模式空间中读取多行并且操作得非常好,但是需要更多的努力.Sed有一组命令允许这种类型的东西......这是一个指向命令的链接sed摘要。这是我发现的最好的,让我滚动。
然而,一旦开始使用sed的微命令,就忘记了“单线”的想法。将它打扮成结构化程序是有用的,直到你感觉到它...它非常简单,同样不同寻常。您可以将其视为文本编辑的“汇编语言”。
总结:对于简单的事情使用sed,也许更多一些,但总的来说,当它超越单线工作时,大多数人更喜欢别的东西...... 我会让别人提出别的建议......我真的不确定最好的选择是什么(我会使用sed,但那是因为我不太了解perl。)
sed '/^a test$/{
$!{ N # append the next line when not on the last line
s/^a test\nPlease do not$/not a test\nBe/
# now test for a successful substitution, otherwise
#+ unpaired "a test" lines would be mis-handled
t sub-yes # branch_on_substitute (goto label :sub-yes)
:sub-not # a label (not essential; here to self document)
# if no substituion, print only the first line
P # pattern_first_line_print
D # pattern_ltrunc(line+nl)_top/cycle
:sub-yes # a label (the goto target of the 't' branch)
# fall through to final auto-pattern_print (2 lines)
}
}' alpha.txt
这里是相同的剧本,浓缩成显然难以阅读和使用的内容,但有些人会怀疑地称之为单行
sed '/^a test$/{$!{N;s/^a test\nPlease do not$/not a test\nBe/;ty;P;D;:y}}' alpha.txt
这是我的命令“cheat-sheet”
: # label
= # line_number
a # append_text_to_stdout_after_flush
b # branch_unconditional
c # range_change
d # pattern_delete_top/cycle
D # pattern_ltrunc(line+nl)_top/cycle
g # pattern=hold
G # pattern+=nl+hold
h # hold=pattern
H # hold+=nl+pattern
i # insert_text_to_stdout_now
l # pattern_list
n # pattern_flush=nextline_continue
N # pattern+=nl+nextline
p # pattern_print
P # pattern_first_line_print
q # flush_quit
r # append_file_to_stdout_after_flush
s # substitute
t # branch_on_substitute
w # append_pattern_to_file_now
x # swap_pattern_and_hold
y # transform_chars
答案 5 :(得分:0)
我意识到这不是你所问的可能它不值得使用sed吗?
python解决方案怎么样?它将目录作为第一个参数传递给脚本,并在编写时替换完全 <Directory
元素,而仅将None
更改为All
并将更改写回文件。它还可以使用不同的缩进级别,同时保留原始缩进。适用于python2和python3。
毕竟我假设你有sed你也可能有python。
#!/usr/bin/env python
import re
r = re.compile(r'(<Directory /var/www/>\s+Options Indexes FollowSymLinks\s+AllowOverride )None(\s+Require all granted\s+</Directory>)', re.MULTILINE)
for root, dirs, files in os.walk(sys.argv[1]):
for file_name in files:
if file_name.endswith('.conf'):
file_path = os.path.join(root, file_name)
with open(file_path) as fp:
data = r.sub(r'\1All\2', fp.read())
with open(file_path, 'w+') as fp:
fp.write(data)