我创建了一个JSON文件,在这种情况下包含:
{"ipaddr":"10.1.1.2","hostname":"host2","role":"http","status":"active"},
{"ipaddr":"10.1.1.3","hostname":"host3","role":"sql","status":"active"},
{"ipaddr":"10.1.1.4","hostname":"host4","role":"quad","status":"active"},
另一方面,我有一个带有值的变量,例如:
arr="10.1.1.2 10.1.1.3"
来自后续检查服务器状态,例如。对于这些值,我想将状态字段更改为"inactive"
。换句话说,grep
主机并更改其"status"
值。
预期产出:
{"ipaddr":"10.1.1.2","hostname":"host2","role":"http","status":"inactive"},
{"ipaddr":"10.1.1.3","hostname":"host3","role":"sql","status":"inactive"},
{"ipaddr":"10.1.1.4","hostname":"host4","role":"quad","status":"active"},
答案 0 :(得分:2)
$ arr="10.1.1.2 10.1.1.3"
$ awk -v arr="$arr" -F, 'BEGIN { gsub(/\./,"\\.",arr); gsub(/ /,"|",arr) }
$1 ~ "\"(" arr ")\"" { sub(/active/,"in&") } 1' file
{"ipaddr":"10.1.1.2","hostname":"host2","role":"http","status":"inactive"},
{"ipaddr":"10.1.1.3","hostname":"host3","role":"sql","status":"inactive"},
{"ipaddr":"10.1.1.4","hostname":"host4","role":"quad","status":"active"},
答案 1 :(得分:2)
版本1 :
使用简单的基于正则表达式的转换。这可以通过几种方式完成。从最初的问题来看,ipaddr列表在arr
中是变量。使用Bash env变量的示例:
$ export var="... ..."
通过命令行参数提供此信息是一种可能的解决方案。
#!/usr/bin/perl
my %inact; # ipaddr to inactivate
my $arr=$ENV{arr} ; # from external var (export arr=...)
## $arr=shift; # from command line arg
for( split(/\s+/, $arr)){ $inact{$_}=1 }
while(<>){ # one "json" line at the time
if(/"ipaddr":"(.*?)"/ and $inact{$1}){
s/"active"/"inactive"/}
print $_;
}
版本2 :
使用Json解析器,我们可以进行更复杂的转换;由于输入不是真正的JSON,我们当时会处理一行“几乎是json”:
use JSON;
use strict;
my ($line, %inact);
my $arr=$ENV{arr} ;
for( split(/\s+/, $arr)){ $inact{$_}=1 }
while(<>){ # one "json" line at the time
if(/^\{.*\},/){
s/,\n//;
$line = from_json( $_);
if($inact{$line->{ipaddr}}){
$line->{status} = "inactive" ;}
print to_json($line), ",\n"; }
else { print $_;}
}
答案 2 :(得分:2)
这是一个快速perl
“环绕式单行”:使用JSON
模块和slurps with the -0
switch:
perl -MJSON -n0E '$j = decode_json($_);
for (@{$j->{hosts}}){$_->{status}=inactive if $_->{ipaddr}=~/2|3/} ;
say to_json( $j->{hosts}, {pretty=>1} )' status_data.json
可能更好或可能违反map
的PBP建议:
perl -MJSON -n0E '$j = decode_json($_);
map { $_->{status}=inactive if $_->{ipaddr}=~/2|3/ } @{ $j->{hosts} } ;
say to_json( $j->{hosts} )' status_data.json
使用jq
重置状态的shell脚本也是可能的。这是使用jq
解析和输出JSON更改的快速方法:
cat status_data.json| jq -r '.hosts |.[] |
select(.ipaddr == "10.1.1.2"//.ipaddr == "10.1.1.3" )' |jq '.status = "inactive"'
编辑在之前的评论中,我不确定OP是否对应用程序更感兴趣,而不是快速搜索和替换(关于短语“另一方...... “和”检查服务器状态“)。以下是脚本形式的(仍然很简单的)perl
方法:
use v5.16; #strict, warnings, say
use JSON ;
use IO::All;
my $status_data < io 'status_data.json';
my $network = JSON->new->utf8->decode($status_data) ;
my @changed_hosts= qw/10.1.1.2 10.1.1.3/;
sub status_report {
foreach my $host ( @{ $network->{hosts} }) {
say "$host->{hostname} is $host->{status}";
}
}
sub change_status {
foreach my $host ( @{ $network->{hosts} }){
foreach (@changed_hosts) {
$host->{status} = "inactive" if $host->{ipaddr} eq $_ ;
}
}
status_report;
}
defined $ENV{CHANGE_HAPPENED} ? change_status : status_report ;
该脚本读取JSON文件status_data.json
(使用IO::All
非常有趣),然后使用JSON
将其解码为哈希。很难判断这是否是一个完整的解决方案,因为如果您正在“监控”主机状态,那么我们应该定期检查JSON数据文件并将其与我们的哈希进行比较,然后在发生更改时运行脚本的主体
要模拟发生的更改,您可以使用CHANGE_HAPPENED
(或export CHANGE_HAPPENED=1
,如果在setenv
中)和tcsh
以及unset CHANGE_HAPPENED
在您的环境中定义/取消定义status_report()
然后,脚本将更新消息和散列或“报告”。为了完成此操作,我们应更新哈希值中的数据,以定期或在事件发生时匹配数据文件。可以更改@inactive_hosts
子例程,以便在@active_hosts
告知它时执行update_status()
和if ( something_happened() ) { update_status() }
的数组:status_data.json
,等。
希望有所帮助。
<强> {
"hosts":[
{"ipaddr":"10.1.1.2","hostname":"host2","role":"http","status":"active"},
{"ipaddr":"10.1.1.3","hostname":"host3","role":"sql","status":"active"},
{"ipaddr":"10.1.1.4","hostname":"host4","role":"quad","status":"active"}
]
}
强>
~/ % perl network_status_json.pl
host2 is active
host3 is active
host4 is active
~/ % export CHANGE_HAPPENED=1
~/ % perl network_status_json.pl
host2 is inactive
host3 is inactive
host4 is active
<强>输出:强>
{{1}}
答案 3 :(得分:1)
#!/bin/ksh
# your "array" of IP
arr="10.1.1.2 10.1.1.3"
# create and prepare temporary file for sed action
SedAction=/tmp/Action.sed
# --- for/do generating SedAction --------
echo "#sed action" > ${SedAction}
#take each IP from the arr variable one by one
for IP in ${arr}
do
# prepare for a psearch pattern use
IP_RE="$( echo "${IP}" | sed 's/\./\\./g' )"
# generate sed action in temporary file.
# final action will be like:
# s/\("ipaddr":"10\.1\.1\.2".*\)"active"}/\1"inactive"}/;t
# escape(double) \ for in_file espace, escape(simple) " for this line interpretation
echo "s/\\\(\"ipaddr\":\"${IP_RE}\".*\\\)\"active\"}/\\\1\"inactive\"}/;t" >> ${SedAction}
done
# --- sed generating sed action ---------------
echo "${arr}" \
| tr " " "\n" \
| sed 's/\./\\./g
s#.*#s/\\("ipaddr":"&".*\\)"active"}/\\1"inactive"}/;t#
' \
> ${SedAction}
# core of the process (use -i for inline editing or "double" redirection for non GNU sed)
sed -f ${SedAction} YourFile
# clean temporary file
rm ${SedAction}
自我评论,在ksh / AIX中测试过。 2根据你想要做的动作生成SedAction的方法(如果有的话)。你只需要一个工作,我更喜欢第二个
答案 4 :(得分:1)
在Perl中使用JSON
模块确实非常简单。
use strict;
use warnings;
use JSON qw/ from_json to_json /;
my $json = JSON->new;
my $data = from_json(do { local $/; <DATA> });
my $arr = "10.1.1.2 10.1.1.3";
my %arr = map { $_ => 1 } split ' ', $arr;
for my $item (@$data) {
$item->{status} = 'inactive' if $arr{$item->{ipaddr}};
}
print to_json($data, { pretty => 1 }), "\n";
__DATA__
[
{"ipaddr":"10.1.1.2","hostname":"host2","role":"http","status":"active"},
{"ipaddr":"10.1.1.3","hostname":"host3","role":"sql","status":"active"},
{"ipaddr":"10.1.1.4","hostname":"host4","role":"quad","status":"active"}
]
<强>输出强>
[
{
"role" : "http",
"hostname" : "host2",
"status" : "inactive",
"ipaddr" : "10.1.1.2"
},
{
"hostname" : "host3",
"role" : "sql",
"ipaddr" : "10.1.1.3",
"status" : "inactive"
},
{
"ipaddr" : "10.1.1.4",
"status" : "active",
"hostname" : "host4",
"role" : "quad"
}
]