0

我有一些输出需要解析为如下所示的数组。条目数可以更改。

interface  : eth1
ip address : 1.1.1.1        [Active]
subnet mask: 255.255.255.0
router     : 1.1.1.2
name server: 1.1.1.3
dhcp server: 1.1.1.4
lease time : 86400
last update: Fri Jul 5 00:11:12 UTC 2013
expiry     : Sat Jul 06 00:11:08 UTC 2013
reason     : BOUND

interface  : eth2
ip address : 2.2.2.2        [Active]
subnet mask: 255.255.255.0
router     : 2.2.2.3
name server: 2.2.2.4
dhcp server: 2.2.2.5
lease time : 86400
last update: Fri Jul 5 03:03:41 UTC 2013
expiry     : Sat Jul 06 03:03:39 UTC 2013
reason     : REBOOT

每个部分都以界面开头,以原因结尾,原因后面的空行。

我对 bash 脚本很陌生,并且几乎尝试了所有我能想到的将每个部分放入一个变量的方法,但我似乎无法让它工作。如果这是任何其他语言......我可以在心跳中做到这一点!

基本上我想要的是一个数组,其中包含每个部分之间的所有细节(这些细节也可以改变并且没有那么多行)。

我用 awk、sed、grep 等尝试了许多不同的方法……它们似乎都没有让我到达我想去的地方。

它最终应该是什么样子:

$output_array[$1]=
interface  : eth1
ip address : 1.1.1.1        [Active]
subnet mask: 255.255.255.0
router     : 1.1.1.2
name server: 1.1.1.3
dhcp server: 1.1.1.4
lease time : 86400
last update: Fri Jul 5 00:11:12 UTC 2013
expiry     : Sat Jul 06 00:11:08 UTC 2013
reason     : BOUND

$output_array[$2]=
interface  : eth1
ip address : 1.1.1.1        [Active]
subnet mask: 255.255.255.0
router     : 1.1.1.2
name server: 1.1.1.3
dhcp server: 1.1.1.4
lease time : 86400
last update: Fri Jul 5 00:11:12 UTC 2013
expiry     : Sat Jul 06 00:11:08 UTC 2013
reason     : BOUND

谁能指出我正确的方向?谢谢!

我尝试过的一个例子,信息没有被拆分,或者我做错了什么!

output_array=echo $output | awk -v x="^$" -v n=1 '$0 ~ x {n++; next}{print}'
for items in $output_array; do
echo "ENTRY: $items"
done
4

4 回答 4

1

一种肮脏的做法:

$ cnt=$(gawk -v RS='\n\n' 'END{print NR}' file)
$ for ((i=1;i<=cnt;i++)); do 
    a+=("$(gawk -v l="$i" -v RS='\n\n' 'NR==l' file)"); 
done

$ echo "${a[0]}"
interface  : eth1
ip address : 1.1.1.1        [Active]
subnet mask: 255.255.255.0
router     : 1.1.1.2
name server: 1.1.1.3
dhcp server: 1.1.1.4
lease time : 86400
last update: Fri Jul 5 00:11:12 UTC 2013
expiry     : Sat Jul 06 00:11:08 UTC 2013
reason     : BOUND

$ echo "${a[1]}"
interface  : eth2
ip address : 2.2.2.2        [Active]
subnet mask: 255.255.255.0
router     : 2.2.2.3
name server: 2.2.2.4
dhcp server: 2.2.2.5
lease time : 86400
last update: Fri Jul 5 03:03:41 UTC 2013
expiry     : Sat Jul 06 03:03:39 UTC 2013
reason     : REBOOT
于 2013-07-05T04:39:09.557 回答
1

这是给你的一个技巧:

IFS=$'\x01'
output_array=($(cat someoutput | sed -e "s/^$/$IFS/"))
IFS=$' \t\n'

它将 bash 设置为按不可打印字符拆分单词,然后在所有空白行中插入该不可打印字符。然后它将 IFS 设置回其默认值,因此它不会干扰脚本的其余部分。

于 2013-07-05T04:39:16.760 回答
0

我已经使用@that other guy 的建议和更多研究使它工作

有人可以改进吗?

output+=$'\n'
x=0
while read -r line
do
    if [ -z "$line" ]; then
        output_array[$x]=$data
        unset data
        let x++                
    else
        data+=$'\n'
        data+=$line
    fi
done <<< "$output"

for j in "${output_array[@]}"
do
    echo "$j"
done
于 2013-07-05T07:10:59.320 回答
0

@jivetek - 这不是对您所写内容的改进,但令我困扰的是,我无法根据@thatotherguy 发布的解决方案获得解决方案,以按预期工作。这是一个使用两个不可打印字符的版本,以及一些我不明白的 bash 魔法。需要注意的是,“\002”字符留在数组元素中。它需要第二次通过数组来清理每个元素,但这可能很容易在你的脚本中的其他地方做(大概你需要遍历这些数据)

IFS=$'\001'
IN=`awk '/^$/ {print "\001"} { print $0 "\002" }' input`
IFS=$'\001\n' read -a oarr3 -d$IFS <<< $IN
IFS=$' \t\n'

其中输入只是您在名为“输入”的文件中的数据。

从这个问题中找到“读取”命令。我不明白的“魔术”是为什么 IFS 的双重分配与“-d”标志一起工作,而我认为我不需要像它们这样的东西。

oarr3 的内容是我所期望的(主要是):

declare -a oarr3='([0]="interface  : eth1 ip address : 1.1.1.1        [Active] subnet mask: 255.255.255.0 router     : 1.1.1.2 name server: 1.1.1.3 dhcp server: 1.1.1.4 lease time : 86400 last update: Fri Jul 5 00:11:12 UTC 2013 expiry     : Sat Jul 06 00:11:08 UTC 2013 reason     : BOUND " [1]=" interface  : eth2 ip address : 2.2.2.2        [Active] subnet mask: 255.255.255.0 router     : 2.2.2.3 name server: 2.2.2.4 dhcp server: 2.2.2.5 lease time : 86400 last update: Fri Jul 5 03:03:41 UTC 2013 expiry     : Sat Jul 06 03:03:39 UTC 2013 reason     : REBOOT")'

但是,就像我说的,“\002”字符仍然在每个数组元素中,并且“\002”字符之后也可能有一个空格:

echo "${oarr3[0]}" | tr '\002' '\n'
interface  : eth1
 ip address : 1.1.1.1        [Active]
 subnet mask: 255.255.255.0
 router     : 1.1.1.2
 name server: 1.1.1.3
 dhcp server: 1.1.1.4
 lease time : 86400
 last update: Fri Jul 5 00:11:12 UTC 2013
 expiry     : Sat Jul 06 00:11:08 UTC 2013
 reason     : BOUND
[0]

这是原始数据的视图:

cat -etv <<< ${oarr3[0]} interface  : eth1^B ip address : 1.1.1.1        [Active]^B subnet mask: 255.255.255.0^B router     : 1.1.1.2^B name server: 1.1.1.3^B dhcp server: 1.1.1.4^B lease time : 86400^B last update: Fri Jul 5 00:11:12 UTC 2013^B expiry     : Sat Jul 06 00:11:08 UTC 2013^B reason     : BOUND^B $

看起来第二个元素中有一个前导“\002”。这可能是因为我不得不离开 awk 输出的返回值,并将它们包含在第二个 IFS 声明中。这一切都可以通过在需要处理数据时重新唤醒来解决。

外壳版本:

sh -version
GNU bash, version 3.2.25(1)-release (x86_64-redhat-linux-gnu)
Copyright (C) 2005 Free Software Foundation, Inc.
于 2013-07-05T18:37:26.897 回答