【问题标题】:How to split a delimited string into an array in awk?如何在awk中将分隔字符串拆分为数组?
【发布时间】:2011-12-22 00:28:14
【问题描述】:

当字符串中包含管道符号| 时如何拆分字符串。 我想将它们拆分为数组。

我试过了

echo "12:23:11" | awk '{split($0,a,":"); print a[3] a[2] a[1]}'

效果很好。如果我的字符串类似于"12|23|11",那么如何将它们拆分成一个数组?

【问题讨论】:

  • 请注意,您的输出是连接数组元素,没有分隔符。如果您希望它们用 OFS 分隔,请在它们之间添加逗号,使 print 将它们视为单独的参数。
  • 或者你可以使用sed:echo "12:23:11" | sed "s/.*://"
  • @slushy:你的命令根本不是提问者需要的。您的命令(echo "12:23:11" | sed "s/.*://")删除所有内容,直到(包括)最后一个“:”,只保留“11”......它可以获取最后一个数字,但需要修改(以一种难以阅读的方式) 来获得第二个数字,等等。awk(和 awk 的拆分)更加优雅和可读。
  • 如果你需要在单个字符上分割你可以使用cut

标签: awk


【解决方案1】:

你试过了吗:

echo "12|23|11" | awk '{split($0,a,"|"); print a[3],a[2],a[1]}'

【讨论】:

  • @Mohamed Saigh,如果你在 Solaris 上,你需要使用 /usr/xpg4/bin/awk,给定字符串长度。
  • '不适合我'。特别是在回显值之间有冒号,并且拆分设置为在“|”上拆分???错字?祝大家好运。
  • 最好有一些语法解释。
  • 这在 GNU awk 中不起作用,因为 split 的第三个参数是正则表达式,而 | 是特殊符号,需要转义。使用split($0, a, "\|")
  • @WhiteWind:另一种“确保”| 被视为字符而不是特殊符号的方法是将其放在[] 之间:即split($0, a, "[|]") # 我更喜欢这个比'\|',在某些情况下,尤其是正则表达式的某些变体(perl vs grep vs .. others?)可以有“|”字面意思和“\|”被视为正则表达式分隔符,而不是相反的... ymmv
【解决方案2】:

要将字符串拆分为awk 中的数组,我们使用函数split()

awk '{split($0, array, ":")}'
#           \/  \___/  \_/
#           |     |     |
#       string    |     delimiter
#                 |
#               array to store the pieces

如果没有给出分隔符,则使用FS,默认为空格:

$ awk '{split($0, array); print array[2]}' <<< "a:b c:d e"
c:d

我们可以给一个分隔符,例如::

$ awk '{split($0, array, ":"); print array[2]}' <<< "a:b c:d e"
b c

相当于通过FS设置:

$ awk -F: '{split($0, array); print array[1]}' <<< "a:b c:d e"
b c

在 GNU Awk 中,您还可以提供分隔符作为正则表达式:

$ awk '{split($0, array, ":*"); print array[2]}' <<< "a:::b c::d e
#note multiple :
b c

甚至可以通过使用它的第四个参数来查看每一步的分隔符是什么:

$ awk '{split($0, array, ":*", sep); print array[2]; print sep[1]}' <<< "a:::b c::d e"
b c
:::

让我们引用man page of GNU awk

split(string, array [, fieldsep [, seps ] ])

string 分成由 fieldsep 分隔的片段,并将片段存储在 array 中,将分隔字符串存储在 seps 阵列。第一个片段存储在array[1],第二个片段存储在array[2],以此类推。第三个参数 fieldsep 的字符串值是一个正则表达式,描述在哪里拆分 string(就像 FS 可以是一个正则表达式,描述在哪里拆分输入记录)。如果省略 fieldsep,则使用 FS 的值。 split() 返回创建的元素数。 sepsgawk 扩展,seps[i]array[i]array[i+1] 之间的分隔符字符串。如果 fieldsep 是单个空格,则任何前导空格进入 seps[0],任何尾随空格进入 seps[n],其中 nsplit() 的返回值(即数组中的元素个数)。

【讨论】:

    【解决方案3】:

    请更具体! “它不起作用”是什么意思? 发布确切的输出(或错误消息)、您的操作系统和 awk 版本:

    % awk -F\| '{
      for (i = 0; ++i <= NF;)
        print i, $i
      }' <<<'12|23|11'
    1 12
    2 23
    3 11
    

    或者,使用拆分:

    % awk '{
      n = split($0, t, "|")
      for (i = 0; ++i <= n;)
        print i, t[i]
      }' <<<'12|23|11'
    1 12
    2 23
    3 11
    

    编辑:在 Solaris 上,您需要使用 POSIX awk (/usr/xpg4/bin/awk) 才能正确处理 4000 个字段。

    【讨论】:

    • for(i = 0for(i = 1 ?
    • i = 0,因为我在后面使用了 ++i(不是 i++)。
    • 好的 - 我没有注意到这一点。我坚信for (i = 1; i &lt;= n; ++i) 更具可读性...
    【解决方案4】:

    我不喜欢echo "..." | awk ... 解决方案,因为它会调用不必要的forkexecsystem 调用。

    我更喜欢稍微扭曲的 Dimitre 解决方案

    awk -F\| '{print $3 $2 $1}' <<<'12|23|11'
    

    或者更短的版本:

    awk -F\| '$0=$3 $2 $1' <<<'12|23|11'
    

    在这种情况下,输出记录放在一起,这是一个真实的条件,所以它会被打印出来。

    在这种特定情况下,stdin 重定向可以通过设置 内部变量来避免:

    awk -v T='12|23|11' 'BEGIN{split(T,a,"|");print a[3] a[2] a[1]}'
    

    我使用 有一段时间了,但在 中,这可以通过内部字符串操作来管理。在第一种情况下,原始字符串由内部终止符分割。在第二种情况下,假定字符串始终包含由一个字符分隔符分隔的数字对。

    T='12|23|11';echo -n ${T##*|};T=${T%|*};echo ${T#*|}${T%|*}
    T='12|23|11';echo ${T:6}${T:3:2}${T:0:2}
    

    所有情况下的结果都是

    112312
    

    【讨论】:

    • 我认为最终结果应该是 awk 数组变量引用,无论给出的打印输出示例如何。但是您错过了一个非常简单的 bash 案例来提供您的最终结果。 T='12:23:11';回声 ${T//:}
    • @DanielListon 你是对的!谢谢!我不知道这个bash表达式中可以留下尾随的/...
    【解决方案5】:

    我知道这是一个老问题,但我想也许有人喜欢我的把戏。特别是因为此解决方案不限于特定数量的项目。

    # Convert to an array
    _ITEMS=($(echo "12|23|11" | tr '|' '\n'))
    
    # Output array items
    for _ITEM in "${_ITEMS[@]}"; do
      echo "Item: ${_ITEM}"
    done
    

    输出将是:

    Item: 12
    Item: 23
    Item: 11
    

    【讨论】:

      【解决方案6】:

      实际上awk 有一个称为“输入字段分隔符变量”link 的功能。这是如何使用它。它不是真正的数组,但它使用内部 $ 变量。对于分割一个简单的字符串,它更容易。

      echo "12|23|11" | awk 'BEGIN {FS="|";} { print $1, $2, $3 }'
      

      【讨论】:

        【解决方案7】:

        开玩笑? :)

        echo "12|23|11" | awk '{split($0,a,"|"); print a[3] a[2] a[1]}'怎么样

        这是我的输出:

        p2> echo "12|23|11" | awk '{split($0,a,"|"); print a[3] a[2] a[1]}'
        112312
        

        所以我想它毕竟可以工作..

        【讨论】:

        • 是因为字符串的长度吗?因为,我的字符串长度是 4000。任何想法
        【解决方案8】:
        echo "12|23|11" | awk '{split($0,a,"|"); print a[3] a[2] a[1]}'
        

        应该可以。

        【讨论】:

          【解决方案9】:
          echo "12|23|11" | awk '{split($0,a,"|"); print a[3] a[2] a[1]}'
          

          【讨论】:

            【解决方案10】:

            挑战:解析和存储带有空格的分割字符串,并将它们插入到变量中。

            解决方案: 对您来说最好和简单的选择是将字符串列表转换为数组,然后将其解析为带有索引的变量。这是一个如何转换和访问数组的示例。

            示例:解析每一行的磁盘空间统计信息:

            sudo df -k | awk 'NR>1' | while read -r line; do
               #convert into array:
               array=($line)
            
               #variables:
               filesystem="${array[0]}"
               size="${array[1]}"
               capacity="${array[4]}"
               mountpoint="${array[5]}"
               echo "filesystem:$filesystem|size:$size|capacity:$capacity|mountpoint:$mountpoint"
            done
            
            #output:
            filesystem:/dev/dsk/c0t0d0s1|size:4000|usage:40%|mountpoint:/
            filesystem:/dev/dsk/c0t0d0s2|size:5000|usage:50%|mountpoint:/usr
            filesystem:/proc|size:0|usage:0%|mountpoint:/proc
            filesystem:mnttab|size:0|usage:0%|mountpoint:/etc/mnttab
            filesystem:fd|size:1000|usage:10%|mountpoint:/dev/fd
            filesystem:swap|size:9000|usage:9%|mountpoint:/var/run
            filesystem:swap|size:1500|usage:15%|mountpoint:/tmp
            filesystem:/dev/dsk/c0t0d0s3|size:8000|usage:80%|mountpoint:/export
            

            【讨论】:

              【解决方案11】:
              awk -F'['|'] -v '{print $1"\t"$2"\t"$3}' file <<<'12|23|11'
              

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 2016-10-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2018-07-23
                相关资源
                最近更新 更多