我有一个包含我的Nagios主机的文件,我需要更改一些主机父母,而且我对如何用脚本解决这个问题毫无头绪。
该文件位于freebsd服务器上,我正在使用bash作为我喜欢的shell。
文件的结构如下所示:
define host{
use template-here
name testname
alias testalias
check_command check-host-alive
max_check_attempts 5
contact_groups group1
parents parent1.abc.local //2. Change this line
notification_interval 240
notification_period none
notification_options d,r
register 0
}
define host{
host_name host2234.abc.local //1. Search for this line
address 10.10.10.5
notification_period 07-21
use testname
}
我可以100%确定并且搜索文件的唯一模式是host_name行,它总是包含4个数字。
如果我执行grep,“grep -B10 -m1 2234.abc文件”我可以100%确定我将获得正在搜索的主机的正确父级包含在结果中,并且这是我被困的地方。 如何继续更改grep结果中的父项,然后将父项的新值保存到文件中。并将所有这些放在循环中,因为它不止一个主机我需要更改父级。
上面实际grep的输出如下所示:
grep -B10 -m1 2234.abc stack
max_check_attempts 5
contact_groups group1
parents parent1.abc.local
notification_interval 240
notification_period none
notification_options d,r
register 0
}
define host{
host_name host2234.abc.local
同一文件中另一个主机的第二个示例,其中包含其他行,并且具有与第一个示例相同的父级。
grep -B10 -m1 2235.abc stack
contact_groups group2
parents parent1.abc.local
notification_interval 240
notification_period none
notification_options d,r
register 0
active_checks_enabled 1
}
define host{
host_name host2235.abc.local
为了避免混淆,我不可能只通过文件替换父线上的整个字符串,因为我没有移动连接到当前父节点的所有主机。
我还有其他几个类似的用例,其中相同的逻辑适用,所以如果有人能给我一个正确的方向,让轮子旋转到说话,而不是仅仅发布一个完整的解决方案,我会非常高兴。 好吧,除非这是我在搜索和谷歌搜索时找不到的一个帖子的副本。
谢谢!
使用Ed Mortons脚本更新结果,它只打印文件内容而不更改行:
root@workdawg:script # cat tst.awk
BEGIN { RS=""; ORS="\n\n" }
/2234\.abc/ { sub(/parents[^\n]+/,"parents\t\t\t*** Eureka! ***",prev) }
NR>1 { print prev }
{ prev = $0 }
END { print prev }
root@workdawg:script # awk -f tst.awk stack
define host{
use template-here
name testname
alias testalias
check_command check-host-alive
max_check_attempts 5
contact_groups group1
parents parent3.abc.local
notification_interval 240
notification_period none
notification_options d,r
register 0
}
define host{
host_name host2234.abc.local
address 10.10.10.5
notification_period 07-21
use testname
}
答案 0 :(得分:0)
肯定有很多方法可以执行此操作。此示例使用带有grep -n
和sed
的bash脚本来完成此任务:
#!/bin/sh
file="whatever.conf"
# Get the line numbers from the text
find_grep_line_number() {
local line_txt=$1
local x
i=0
# Isolate the line number from grep -n before the :
local REG_EX="^(.*):"
if [[ $line_txt =~ $REG_EX ]]
then
local n=${#BASH_REMATCH[*]}
for (( x=0; x<$n; x++ ));
do
#echo "$x: ${BASH_REMATCH[$x]}"
i=${BASH_REMATCH[$x]}
done
fi
}
line_host_txt=`grep -n "^host_name" $file`
find_grep_line_number $line_host_txt
host_line=$i
line_parents_txt=`grep -n "^parents" $file`
find_grep_line_number $line_parents_txt
parents_line=$i
replacement_parents_line="parents parent1.abc.local"
# Replace the parents line with a new line.
rslts=`sed -i "$parents_line c\$replacement_parents_line" $file`
我没有测试这个脚本但它应该可以工作(LoL).. sed
非常适合做这些事情(http://www.cyberciti.biz/faq/unix-linux-sed-match-replace-the-entire-line-command/)
答案 1 :(得分:0)
你没有显示你的预期输出,所以这是猜测,但这是你想要的吗?
$ cat tst.awk
BEGIN { RS=""; ORS="\n\n" }
/2234\.abc/ { sub(/parents[^\n]+/,"parents\t\t\t*** Eureka! ***",prev) }
NR>1 { print prev }
{ prev = $0 }
END { print prev }
$ awk -f tst.awk file
define host{
use template-here
name testname
alias testalias
check_command check-host-alive
max_check_attempts 5
contact_groups group1
parents *** Eureka! ***
notification_interval 240
notification_period none
notification_options d,r
register 0
}
define host{
host_name host2234.abc.local //1. Search for this line
address 10.10.10.5
notification_period 07-21
use testname
}
上面一次一个地读取每个空白行分隔的文本块(由RS=""
提供),并始终在最近一次读取之前打印记录。如果当前记录包含2234.abc
,则sub()
会在打印之前替换上一记录中的parent
行。