【问题标题】:Using array inside awk in shell script在 shell 脚本中使用 awk 中的数组
【发布时间】:2016-06-18 23:36:10
【问题描述】:

我对 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

我怎样才能完成以上期望?

【问题讨论】:

  • 您将awkbash/ksh 语法合并为一个脚本。 awk 不会理解 IFS&lt;&lt;&lt;read 与 shell 语法相同。或${!array[@]} 就此事。用简单的awk 编写所有这些(对于您的预期输出)应该没有任何问题。抛弃 shell 语法并简化!查找awksplilt() 函数的示例来解析A:3 E:3 PS:6$2 字段。祝你好运。

标签: arrays shell awk


【解决方案1】:

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

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

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

$ awk -f tst.awk file
ABC
A=3
E=3
PS=6

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

UNIX shell 是一个可以调用 UNIX 工具(find、sort、sed、grep、awk、tr、cut 等)的环境。它有自己的语言来操作(例如创建/销毁)文件和进程以及对工具的调用排序,但它不打算用于操作文本。发明 shell 的人也发明了 awk 让 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》一书。

【讨论】:

    【解决方案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 命令),然后将所有: 转换为=,并将所有空格转换为换行符(@ 987654329@ 命令)。请注意

    1. 这仅是因为第一行末尾有一个空格(否则在块之间获取空行会涉及更多内容)和
    2. 这仅适用于 GNU sed,因为它替换了换行符;有关所有详细信息以及如何使其与 BSD sed 一起使用,请参阅 this fantastic answer

    至于你所尝试的,它几乎有太多的错误,无法尝试逐个修复它:从 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
    

    【讨论】:

    • 您好,感谢您提供的 2 个解决方案。它对我有用:)
    猜你喜欢
    • 2012-11-15
    • 1970-01-01
    • 2021-08-13
    • 1970-01-01
    • 2021-11-11
    • 2020-07-18
    • 2022-01-18
    相关资源
    最近更新 更多