【问题标题】:Unable to separate semi-colon separated line awk无法分隔分号分隔行 awk
【发布时间】:2018-02-05 22:34:45
【问题描述】:

我正在尝试执行以下操作:

  1. 逐行读取文件。
  2. 每一行的结构如下:field1;field2;field3
  3. 使用awk 分隔每个字段,然后进一步处理每个字段

我的sn-p代码是:

while read l
do
n=`echo ${l} | awk --field-separator=";" '{print NF}'`
field1=`echo ${l} | awk --field-separator=";" '{print $1}'`
field2=`echo ${l} | awk --field-separator=";" '{print $2}'`
field3=`echo ${l} | awk --field-separator=";" '{print $3}'`
echo ${n} ${field1} ${field2} ${field3} 
done < temp 

其中 temp 仅包含以下行:

xx;yy;zz  

我在命令行得到的答案是:

1 xx;yy;zz

我不确定我是否理解此输出。任何解释都会很好,因为它确实适用于其他文件。我在 Mac 上工作,而这段代码在 bash 脚​​本中使用 awk

【问题讨论】:

  • 我得到了预期的输出:3 xx yy zz 你使用的是哪个版本的awk
  • awk --version 导致“awk 版本 20070501”
  • @devnull:我认为它只找到一个字段:xx;yy;zz 而不是 xx yy zz
  • 尝试-F';' 而不是--field-separator=';'
  • 永远不要使用字母 el (l) 作为变量名,因为它看起来太像第一个 (1) 并且会混淆你的代码。大写字母 oh (O) 与数字零 (0) 同上。

标签: bash awk


【解决方案1】:

既然可以在纯 bash 中完成,为什么还要 awk?

while IFS=';' read -r field1 field2 field3; do
    echo "Field1: $field1"
    echo "Field2: $field2"
    echo "Field3: $field3"
done < file.txt

或者如果您不知道字段数:

while IFS=';' read -ra fields; do        
    echo "Number of fields: ${#fields[@]}"
    echo "Field1 ${fields[0]}"
done < file.txt

【讨论】:

  • 无需将其传递给另一个变量,如line。你可以做while IFS=';' read -ra fields
  • @konsolebox 完全正确!谢谢,已修复。
  • 关于Why awk when you can do it in pure bash? - 见why-is-using-a-shell-loop-to-process-text-considered-bad-practice
  • @EdMorton 我认为你完全没有抓住重点。在大多数情况下,除非您实际对它们进行处理,否则处理这些行没有任何好处。这就是为什么我们总是在某些时候循环遍历 bash 中的行。您可以使用xargs 提出一些建议,但我想看看它是如何更具可读性的。
  • 不,我完全没有错过重点。您似乎假设 OP 想要使用输入文件中的值调用一些 shell 命令,而我假设他们想要进一步将它们作为文本进行操作,例如重新排列它们,取平均值等。
【解决方案2】:

您的 awk 不知道 --field-separator=";" 的含义,所以当您这样做时:

awk --field-separator=";" '{print $1}'

您的 awk 仍在使用空间的默认 FS,因此 $1 包含您的整个输入行,而 $2 和 $3 为空。使用-F';'设置FS。

在如何编写你想要的脚本方面,你太离谱了。如果您告诉我们更多关于“处理每个字段”是什么的信息,我们可以为您提供帮助。

【讨论】:

  • 为何如此居高临下? --field-separator=";" 在我的机器上工作,不是问题。 awk 手册页甚至指定了它:-F fs or --field-separator fs, Use fs for the input field separator (the value of the FS predefined variable). 至于离题:我同意,但也许你可以提供更好的解决方案,就像其他一些人所做的那样。
  • 这有什么高见?您的 awk 接受或不接受什么并不重要,这就是 OP 遇到的问题,如果您建议其他答案所建议的任何类型的 shell 循环是一个更好的解决方案,那么您也是方式离题(见why-is-using-a-shell-loop-to-process-text-considered-bad-practice),我不能提供更好的解决方案,因为OP没有完全描述这个问题。
【解决方案3】:

这可能是您的 awk 的错误。尝试以下其他格式:

while read l
do
    n=`echo "${l}" | awk -F\; '{print NF}'`
    field1=`echo "${l}" | awk -F\; '{print $1}'`
    field2=`echo "${l}" | awk -F\; '{print $2}'`
    field3=`echo "${l}" | awk -F\; '{print $3}'`
    echo "${n} ${field1} ${field2} ${field3}"
done < temp 

或者

while read l
do
    n=`echo "${l}" | awk -v 'FS=;' '{print NF}'`
    field1=`echo "${l}" | awk -v 'FS=;' '{print $1}'`
    field2=`echo "${l}" | awk -v 'FS=;' '{print $2}'`
    field3=`echo "${l}" | awk -v 'FS=;' '{print $3}'`
    echo "${n} ${field1} ${field2} ${field3}"
done < temp 

或者

while read l
do
    n=`echo "${l}" | awk 'BEGIN{FS=";"}{print NF}'`
    field1=`echo "${l}" | awk 'BEGIN{FS=";"}{print $1}'`
    field2=`echo "${l}" | awk 'BEGIN{FS=";"}{print $2}'`
    field3=`echo "${l}" | awk 'BEGIN{FS=";"}{print $3}'`
    echo "${n} ${field1} ${field2} ${field3}"
done < temp 

也可以尝试其他 awk,例如 mawknawk

【讨论】:

  • 这不是他的 awk 的错误,而是一个特性。或者也许缺少某个功能 (--field-separator) 会更准确。
  • @EdMorton 但是如果不接受该选项,awk 不会显示错误消息吗?如果该功能已被识别但尚未按应有的方式工作,那么我认为这是一个错误。
  • awk --foo 是一些 awk 的有效 awk 脚本(我不确定哪些支持长选项 - GNU 支持但还有什么?)。与 awk --field-separator 类似 - 它减少名为 field 的变量并从中减去名为 separator 的变量的值,或者将其作为 2 个单独的语句进行处理。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-06-14
  • 2015-02-10
  • 2019-09-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多