我的任务是从多个 Apache 服务器中提取数据。任务是打印出:
<Directory ...>
...
</Directory>
其中 +ExecCGI 位于其中。我举个例子来说明一下。假设 Apache 配置文件有许多目录部分,如下所示:
<Directory /var/www/site1/htdocs>
Options +ExecCGI
...
...
</Directory>
...
...
...
<Directory /var/www/site1/Promo>
Options -ExecCGI
...
...
</Directory>
从上面,我只想得到以下输出:
<Directory /var/www/site1/htdocs>
Options +ExecCGI
...
...
</Directory>
我搜索了论坛并找到了一些帖子,其中人们提出了如何打印标签之间的整个部分的问题(我知道如何做到这一点),或者在找到时更改某些文本(同样,我知道如何做到这一点) )。
我将把 +ExecCGI 更改为 -ExecCGI,但更改需要经过审核过程,因此这个问题是这样我可以提取这些数据的。
答案1
perl -l -0777 -ne 'for (m{<Directory.*?</Directory>}gs) {print if /\+ExecCGI/}'
或者使用 GNU grep
:
grep -zPo '(?s)<Directory(?:.(?!</Directory))*?\+ExecCGI.*?</Directory>'
答案2
你也可以使用awk
awk 'BEGIN{RS="</Directory>\n"; ORS=RS} /\+ExecCGI/ {print}' file
答案3
如果您可以使用perl
,这里有一个解决方案:
$ perl -nle '
if (/<Directory/) {
$flag = 1;
}
push @a, $_ if $flag;
if (/<\/Directory/) {
$flag = 0;
if (grep {$_ =~ /\+ExecCGI/} @a) {
push @f, @a;
}
@a = ();
}
END {
print join "\n", @f;
}' file
<Directory /var/www/site1/htdocs>
Options +ExecCGI
...
...
</Directory>
解释
- 每次我们看到
<Directory
,我们就设定$flag = 1
。 - 如果
$flag
为 true(1 在布尔上下文中表示 true),我们将当前条目推送到 array@a
。 - 如果我们看到
</Directory
,这意味着我们完成了该块,我们检查块是否包含+ExecCGI
stringgrep {$_ =~ /\+ExecCGI/
,然后我们推@a
送到@f
。 - 设置
@a
为空数组以处理另一个块。
答案4
这是 Bash 中的一个示例(您应该能够在几乎任何语言中执行类似的操作):
$ cat test.sh
#!/bin/bash
DIR=0
BLOCK=''
while read line
do
if [ $DIR -eq 0 ] ; then
if [[ $(echo $line | grep -i '<Directory') ]] ; then
DIR=1
BLOCK="$line"
fi
else
BLOCK="$BLOCK\n$line"
if [[ $(echo $line | grep -i '</Directory') ]] ; then
if [[ $(echo $BLOCK | grep -i 'Options.*+ExecCGI') ]] ; then
echo -e $BLOCK
fi
DIR=0
BLOCK=""
fi
fi
done
基本上,我们只是在进行过程中保存该块,然后grepping
查看它是否包含我们的模式。
它非常简单,并且可能会在某些边缘情况下出现问题(echo -e
例如,如果您的配置文件中有 \ ,它可能会造成混淆),但您可以扩展基本思想来处理它们。
使用示例:
$ cat test.conf
<Directory /var/www/site1/htdocs>
Options +ExecCGI
1
2
</Directory>
3
4
5
<Directory /var/www/site1/Promo>
Options -ExecCGI
6
7
</Directory>
<Directory /var/www/site1/htdocs>
Options -Whatever +ExecCGI
8
9
</Directory>
$ cat test.conf | bash test.sh
<Directory /var/www/site1/htdocs>
Options +ExecCGI
1
2
</Directory>
<Directory /var/www/site1/htdocs>
Options -Whatever +ExecCGI
8
9
</Directory>