将变量拆分为数组

时间:2013-07-05 03:34:50

标签: bash sed awk grep

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

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 个答案:

答案 0 :(得分: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

答案 1 :(得分:1)

这是你的黑客攻击:

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

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

答案 2 :(得分:0)

我使用了@that其他人的建议和更多的研究

有人可以改进吗?

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

答案 3 :(得分: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'

其中input只是您在“input”文件中的数据。

this so question找到“读取”命令。我不明白的“魔法”是为什么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声明中。当需要处理数据时,可以通过重新唤醒来解决这个问题。

Shell版本:

sh -version
GNU bash, version 3.2.25(1)-release (x86_64-redhat-linux-gnu)
Copyright (C) 2005 Free Software Foundation, Inc.