听起来有点复杂,但实际上并非如此。我们说我们有以下(apache2配置)文件:
[...]
<VirtualHost 123.123.123.123:80>
ServerName one.domain.tld
ServerAlias 1.domain.tld
DocumentRoot "/path/to/anything"
[...]
</VirtualHost>
<VirtualHost 321.321.321.321:80>
ServerName two.domain.tld
ServerAlias 2.domain.tld
DocumentRoot "/path/to/something/else"
[...]
</VirtualHost>
<VirtualHost 123.123.123.123:443>
ServerName one.domain.tld
ServerAlias 1.domain.tld
ServerAlias secure.one.domain.tld
ServerAlias secure.1.domain.tld
DocumentRoot "/path/to/anything"
[...]
</VirtualHost>
<VirtualHost 321.321.321.321:443>
ServerName two.domain.tld
ServerAlias 2.domain.tld
ServerAlias secure.two.domain.tld
ServerAlias secure.2.domain.tld
DocumentRoot "/path/to/another/something/else"
[...]
</VirtualHost>
[...]
我需要知道指向每个文档根目录的(子)域。因为我需要在for循环中运行某些命令,所以单独处理每个DocumentRoot
对我来说很重要。我用bash
和一些其他程序做了一个方法,如下所示:
DOCROOTS="$(egrep -ni '^(DocumentRoot|[ ]*DocumentRoot|\t*DocumentRoot) ?=' ${HTCONF} |sed -r 's/(DocumentRoot|"|'"'"'| | )//gI')"
for DOCROOT in $(echo "${DOCROOTS}"); do
LINE="$(printf ${DOCROOT} |cut -d':' -f1)"
ROOT="$(printf ${DOCROOT} |cut -d':' -f2)"
DOMAINS=$(sed "${LINE},\$d" ${HTCONF} |tac |sed '/VirtualHost/Iq' |tac |egrep -i 'ServerAlias|ServerName' |sed -r 's/(ServerName|ServerAlias| | )//gI')
[... rest of document root specific code goes here ...]
done
说明:
DOCROOTS
DOCROOTS
中的每一行做:
LINE
设置为行号ROOT
设置为文档根sed "${LINE},\$d" ${HTCONF}
- 这会删除$LINE
tac
- 这与rev
非常相似,但不仅仅是反转一行的内容,而是完整的输入sed '/VirtualHost/q'
- 这会删除包含VirtualHost
不区分大小写的行tac
- 这会将完整输入反转回原来的订单egrep -i 'ServerAlias|ServerName'
- 这会捕获仅包含ServerName
或ServerAlias
sed -r 's/(ServerName|ServerAlias| | )//gI'
- 这会删除ServerName
和ServerAlias
指令不区分的情况以及空格和制表符。 printf "${ROOT}\n${DOMAINS}\n\n"
的所需输出将是这样的:
/path/to/anything
one.domain.tld
1.domain.tld
/path/to/something/else
two.domain.tld
2.domain.tld
/path/to/anything
one.domain.tld
1.domain.tld
secure.one.domain.tld
secure.1.domain.tld
/path/to/another/something/else
two.domain.tld
2.domain.tld
secure.two.domain.tld
secure.2.domain.tld
有没有更好的方法来实现这一点(可能使用awk
)?
bash
这是错误的做法吗?我应该考虑使用适当的脚本语言吗?如果是这样,哪一个是值得推荐的?
答案 0 :(得分:2)
awk
救援!
$ awk '/VirtualHost/{s=RS}
/Server(Name|Alias)/{s=s $2 RS}
/DocumentRoot/{gsub("\"",""); print $2,s}' file
/path/to/anything
one.domain.tld
1.domain.tld
/path/to/something/else
two.domain.tld
2.domain.tld
/path/to/anything
one.domain.tld
1.domain.tld
secure.one.domain.tld
secure.1.domain.tld
/path/to/another/something/else
two.domain.tld
2.domain.tld
secure.two.domain.tld
secure.2.domain.tld
<强>解释强>
此awk
脚本的结构是模式{action}对(类似于if / then语句)。我聚合包含服务器(名称|别名)的行的第二个字段,并在找到DocumentRoot时打印带有聚合字段的路径。在VirtualHost中重置聚合字段。初始值和连接是记录分隔符(RS),默认为新行。此外,在打印时剥离引号。
s=s RS $2
默认情况下会在组之间生成空行。
答案 1 :(得分:1)
它仍然不完全清楚,但听起来你需要的是:
$ cat tst.awk
{
gsub(/^[[:space:]]+|[[:space:]]+$/,"")
name = value = $0
sub(/[[:space:]].*/,"",name)
sub(/[^[:space:]]+[[:space:]]*/,"",value)
}
name ~ /^Server/ {
flds = flds ORS value
}
name == "DocumentRoot" {
gsub(/^"|"$/,"",value)
print value flds
print "doing rest of document root specific code ..."
print ""
flds = ""
}
$ awk -f tst.awk file
/path/to/anything
one.domain.tld
1.domain.tld
doing rest of document root specific code ...
/path/to/something/else
two.domain.tld
2.domain.tld
doing rest of document root specific code ...
/path/to/anything
one.domain.tld
1.domain.tld
secure.one.domain.tld
secure.1.domain.tld
doing rest of document root specific code ...
/path/to/another/something/else
two.domain.tld
2.domain.tld
secure.two.domain.tld
secure.2.domain.tld
doing rest of document root specific code ...
这完全取决于&#34;其余的文档特定代码&#34;是 - 如果它更多的文本操作它属于awk但是如果它属于shell的其他东西。