【问题标题】:Trying to assign output of awk command to an array试图将 awk 命令的输出分配给数组
【发布时间】:2013-07-13 07:49:52
【问题描述】:

awk 返回以下输出:

qh1adm 20130711151154 : tp import all QH1 u6 -Dsourcesystems=BFI,EBJ
qh1adm 20130711151155 : tp import all QH1 u6 -Dsourcesystems=E7B,B17  
qh1adm 20130711151200 : tp import all QH1 u6 -Dsourcesystems=BFI,EBJ

我想将它存储在一个数组中,以便计算记录数。如果它只大于 1,那么我想显示这个数组的内容。你能帮忙吗?

非常感谢。

【问题讨论】:

    标签: awk


    【解决方案1】:

    使用 bash/zsh,捕获输出,计算行数,如果符合您的条件则打印出来:

    output=$(awk 'something that returns what you showed in your question')
    nlines=$(wc -l <<< "$output")
    if ((nlines > 1)); then
        echo "$output"
    fi
    

    【讨论】:

    • +1 无视 OP 的要求,只给他他需要的东西 :-)!
    【解决方案2】:
    awk '{s[c++]=$0} END { if (c>1) { for (c in s) { print s[c]; } } }'
    

    【讨论】:

    • 您好卡罗利,感谢您的回复。那么它会是这样的吗: awkcommand '{s[c++]=$0} END { if (c>1) { for (c in s) { print s[c]; } } }'
    • P.S.抱歉,我仍在尝试找出插入换行符和预格式化文本的正确方法。
    • 这两个问题我都不懂,你必须更加具体。我不知道你的 awk 脚本是什么,所以我不知道如何将两者结合起来......但你可以yourawkcommand | awk ...
    【解决方案3】:
    ... | awk 'NR == 1 {first=$0} NR == 2 {print first} NR > 1 {print}'
    

    如果输入中有 1 行或更少的行,这将不输出任何内容。否则它会打印整个输入。它的效率很高,因为它只存储第一行,因此在将整个输入存储在数组中时不会浪费内存。

    【讨论】:

      【解决方案4】:

      您可以将 awk 的输出存储在一个文件中,然后计算文件的行数。

      TEMP_FILE=`mktemp`
      awk_command > $TEMP_FILE
      if [[ `wc -l < $TEMP_FILE` -gt 1 ]]
      then
        cat $TEMP_FILE
      fi
      rm $TEMP_FILE
      

      【讨论】:

      • 您好 beny,感谢您的代码。我插入了上面,它工作得很好!非常感谢您的帮助。
      【解决方案5】:

      以防将来有人阅读本文并想知道如何将多行 awk 输出实际获取到 bash 数组中:

      $ cat ./tst.sh
      # ensure globbing is off and set IFS to a newline after saving original values
      oSET="$-"; set -f; oIFS="$IFS"; IFS=$'\n'
      
      array=( $(
          awk 'BEGIN{
              print "qh1adm 20130711151154 : tp import all QH1 u6 -Dsourcesystems=BFI,EBJ"
              print "qh1adm 20130711151155 : tp import all QH1 u6 -Dsourcesystems=E7B,B17"
              print "qh1adm 20130711151200 : tp import all QH1 u6 -Dsourcesystems=BFI,EBJ"
          }'
      ) )
      
      # restore original IFS and globbing values
      IFS="$oIFS"; set +f -"$oSET"
      
      numElts="${#array[@]}"
      
      if (( numElts > 1 ))
      then
          for (( i=0; i < numElts; i++ ));
          do
              printf "array[%d]: %s\n" "$i" "${array[$i]}"
          done
      fi
      $
      $ ./tst.sh tmp
      array[0]: qh1adm 20130711151154 : tp import all QH1 u6 -Dsourcesystems=BFI,EBJ
      array[1]: qh1adm 20130711151155 : tp import all QH1 u6 -Dsourcesystems=E7B,B17
      array[2]: qh1adm 20130711151200 : tp import all QH1 u6 -Dsourcesystems=BFI,EBJ
      

      但显然,在这种情况下,这些实际上都不是必需的,整个事情可能应该在一个 awk 命令中完成。

      以上内容已更新,以解决下面@CharlesDuffy 提出的问题。

      【讨论】:

      • 这实际上并不安全:array=( $(stuff) )stuff 的输出上进行字符串拆分和全局扩展,因此很难保证结果完全按照您想要的方式返回。更安全的方法是让 awk 发出以 NUL 分隔的条目,并使用 array=(); while read -r -d ''; do array+=( "$REPLY" ); done &lt; &lt;(awk ...) 读取它们。
      • ...更明确一点——假设您在 awk 的输出中有一行仅包含 *;在放入array之前,它将被当前目录中的文件列表替换。
      • 你说得对,全局扩展是一个问题。您能否举例说明字符串拆分何时会成为问题?我真的不想写你建议的循环来填充数组,我宁愿把全局扩展作为一个警告。除了转义打印中的每个 glob 元字符之外,您还有其他建议吗?
      • 另一个选项是使用set -f 禁用通配,并使用set +f 稍后重新启用它。这有点糟糕的形式,原因与更改 IFS 的原因相同(没有明确地将 IFS 更改为单个命令,正如 IFS=... read 所做的那样)——你正在增加某人需要在他们的头脑中拥有的上下文数量了解给定脚本的作用。
      • 我不想做一个 set -f 以防它被禁用,如果这个段被用在一个更大的脚本的中间,但我可以在 @ 之前保存 $- 的值987654332@ 稍后恢复。显然,我也可以保存 IFS 并稍后将其恢复为原始值。让我现在更新脚本,然后请再看一下,看看是否还有其他内容。分词怎么样,在这种情况下真的是一个问题吗?
      猜你喜欢
      • 2017-07-21
      • 1970-01-01
      • 2012-12-12
      • 2012-02-23
      • 2012-07-16
      • 2017-09-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多