在shell脚本中使用awk中的数组

时间:2016-03-05 03:10:07

标签: arrays shell awk

我是Unix shell脚本的新手,并试图获得shell脚本的一些知识。请检查我的要求和我的方法。

我有一个包含数据的输入文件

ABC = A:3 E:3 PS:6 
PQR = B:5 S:5 AS:2 N:2

我正在尝试解析数据并将结果作为

ABC
A=3
E=3
PS=6

PQR
B=5
S=5
AS=2
N=2

可以水平和垂直添加值,因此我尝试使用数组。我正在尝试这样的事情:

myarr=(main.conf | awk -F"=" 'NR!=1 {print $1}'))
echo ${myarr[1]}
# Or loop through every element in the array
for i in "${myarr[@]}"
do
   :
  echo $i
done

awk -F"=" 'NR!=1 {
    print $1"\n"
    STR=$2
    IFS=':' read -r -a array <<< "$STR"
    for i in "${!array[@]}"
    do
    echo "$i=>${array[i]}"
    done

}' main.conf

但是当我将此代码添加到.sh文件并尝试运行它时,我会收到语法错误

$ awk -F"=" 'NR!=1 {
> print $1"\n"
> STR=$2
> FS=  read -r -a array <<< "$STR"
> for i in "${!array[@]}"
> do
>     echo "$i=>${array[i]}"
> done
>
> }' main.conf
awk: cmd. line:4: FS=  read -r -a array <<< "$STR"
awk: cmd. line:4:                        ^ syntax error
awk: cmd. line:5: for i in "${!array[@]}"
awk: cmd. line:5:     ^ syntax error
awk: cmd. line:8: done
awk: cmd. line:8: ^ syntax error

我如何完成上述期望?

2 个答案:

答案 0 :(得分:5)

这是执行您想要的awk代码:

ipengine --profile=/path/to/ipcontroller-engine.json

这是shell脚本(是的,所有shell脚本操作文本都是调用awk):

$ cat tst.awk
BEGIN { FS="[ =:]+"; OFS="=" }
{
    print $1
    for (i=2;i<NF;i+=2) {
        print $i, $(i+1)
    }
    print ""
}

UNIX shell是一个可以从中调用UNIX工具的环境(查找,排序,sed,grep,awk,tr,cut等)。它有自己的语言来操作(例如创建/销毁)文件和进程以及对工具的调用排序,但它并不打算用于操作文本。发明shell的人也发明了awk for shell来调用操作文本。

阅读https://unix.stackexchange.com/questions/169716/why-is-using-a-shell-loop-to-process-text-considered-bad-practice和Arnold Robbins撰写的Effective Awk Programming,4th Edition一书。

答案 1 :(得分:2)

首先,执行你想要的命令:

$ sed 's/ = /\n/;y/: /=\n/' main.conf
ABC
A=3
E=3
PS=6

PQR
B=5
S=5
AS=2
N=2

这将在每一行上替换 = 第一次(仅出现)的换行符(s命令),然后将所有:转换为=和所有空格分为换行符(y命令)。注意

  1. 这只是因为在第一行的末尾有一个空格(否则在块之间获取空行会涉及更多)和
  2. 这只适用于GNU sed,因为它取代了换行符;有关所有细节以及如何使其与BSD sed一起使用,请参阅this fantastic answer
  3. 至于你所尝试的内容,尝试逐个修复它几乎有太多错误:从awk和Bash的狂野混合到整个地方的语法错误。我建议你阅读两篇很好的教程,例如:

    Bash解决方案

    这是一种在Bash中解决同样问题的方法;我没有使用任何阵列。

    #!/bin/bash
    
    # Read line by line into the 'line' variable. Setting 'IFS' to the empty string
    # preserves leading and trailing whitespace; '-r' prevents interpretation of
    # backslash escapes
    while IFS= read -r line; do
    
        # Three parameter expansions:
        # Replace ' = ' by newline (escape backslash)
        line="${line/ = /\\n}"
    
        # Replace ':' by '='
        line="${line//:/=}"
    
        # Replace spaces by newlines (escape backslash)
        line="${line// /\\n}"
    
        # Print the modified input line; '%b' expands backslash escapes
        printf "%b" "$line"
    done < "$1"
    

    输出:

    $ ./SO.sh main.conf
    ABC
    A=3
    E=3
    PS=6
    
    PQR
    B=5
    S=5
    AS=2
    N=2