【问题标题】:Pipe awk output to add to variable inside loop管道 awk 输出以添加到循环内的变量
【发布时间】:2015-11-27 04:20:56
【问题描述】:

我可能会以错误的方式解决这个问题,但我已经尝试了每一种语法,但我遇到了最接近的错误。

我有一个日志文件,我想在其中过滤一组行,如下所示:

Files :  1  1  1  1  1
Files :  3  3  4  4  5
Files :  10 4  2  3  1
Files : 254 1  1  1  1

我所拥有的代码将让我明白这一点,但是,我想使用 awk 来执行所有第一个数字列的加法,在这种情况下给出 268 作为输出(然后在其他列上执行类似的任务)。

我尝试将 awk 输出通过管道传输到循环中以执行最后一步,但它不会添加值,从而引发错误。我认为这可能是由于 awk 将条目作为字符串处理,但由于 bash 不是强类型的,所以没关系?

反正代码是:

 x=0; 
 iconv -f UTF-16 -t UTF-8 "./TestLogs/rbTest.log" | grep "Files :" | grep -v "*.*" | egrep -v "Files : [a-zA-Z]" |awk '{$1=$1}1' OFS="," | awk -F "," '{print $4}' | while read i;
 do
    $x=$((x+=i)); 
done

错误信息:

-bash: 0=1: command not found
-bash: 1=4: command not found
-bash: 4=14: command not found
-bash: 14=268: command not found

我尝试了几种不同的加法语法,但我觉得这与我试图提供的内容有关,而不是加法本身。 目前这只是整数值,但我也希望用浮点数来执行它。

非常感谢任何帮助,我相信有一种不那么复杂的方法来实现这一点,仍在学习中。

【问题讨论】:

  • 您分配给这样的变量:x=$((x+=i))。那就是说这行不通,因为您的任务在子外壳中。有关更多信息,请参阅stackoverflow.com/q/16854280/258523
  • 我认为这与此类似,我在 PoSH 中做过类似的事情,我通常作弊,在下一次管道迭代中将 $_ 分配给临时变量。我不知道如何在 Bash 中完成 - 感谢您的链接,它非常有帮助!

标签: bash variables awk floating-point addition


【解决方案1】:

您可以在 awk 本身中进行计算:

awk '{for (c=3; c<=NF; c++) sum[c]+=$c} END{printf "Total : ";
    for (c=3; c<=NF; c++) printf "%s%s", sum[c], ((c<NF)? OFS:ORS) }' file

输出:

Total : 268 9 8 9 8

这里的sum 是一个关联数组,它保存从#3 开始的每一列的总和。

命令分解:

for (c=3; c<=NF; c++)     # Iterate from 3rd col to last col
sum[c]+=$c                # Add each col value into an array sum with index of col #
END                       # Execute this block after last record
printf "Total : "         # Print literal "Total : "
for (c=3; c<=NF; c++)     # Iterate from 3rd col to last col
printf "%s%s",            # Use printf to format the output as 2 strings (%s%s)
sum[c],                   # 1st one is sum for the given index
((c<NF)? OFS:ORS)         # 2nd is conditional string. It will print OFS if it is not last
                          # col and will print ORS if it is last col.

【讨论】:

  • 好吧,这真的很酷,我不确定我是否明白了所有这些,但它工作得很好。因此,第一部分指示从第 3 列开始并继续移动,直到字段限制,在每个字段中,将条目相加到数组中,该数组也在循环中移动。然后去打印值,也在循环中的数组中移动。 (没有得到 %s%s - 格式?)最后一部分让我完全困惑。请你带我过去好吗?
  • 我在回答中添加了详细说明。
【解决方案2】:

(不是答案,而是格式化的评论)

当我看到长长的 greps 和 awks(以及 seds 等)管道时,我总是会感到不安

... | grep "Files :" | grep -v "*.*" | egrep -v "Files : [a-zA-Z]" | awk '{$1=$1}1' OFS="," | awk -F "," '{print $4}'

可以写成

... | awk '/Files : [^[:alpha:]]/ && !/\*/ {print $4}'

您是使用grep -v "*.*" 过滤掉带点的线条还是带星号的线条?因为你正在实现后者。

【讨论】:

  • 哦,伙计,我知道,我写道,我认为必须有一种方法可以在没有太多管道的情况下做到这一点,请原谅我,我仍在学习绳索,把东西串起来是一个开始。我需要摆脱后者,所以谢天谢地我做对了!我试图确保它仅在带有“文件:”+ 和空格数的行上匹配,然后是数字。我看到这是一个 2 条件语句,您能否解释第一部分,因为它对我来说是一个新结构:[^[:alpha:]]/
  • 你知道,你所做的是完全有效的。 “unix 哲学”是将每个工具用于其设计目的,并将它们与管道链接在一起。您的管道和我的管道之间可能几乎没有性能差异。你肯定在正确的轨道上。 awk 是一种不错的小型编程语言。我建议你花一些时间学习它。然而这一位 awk '{$1=$1}1' OFS=, | awk -F, '{print $4}' 是一个 awk 太多了
  • 这件事[^[:alpha:]] 不是特定于awk 的:它只是一个正则表达式否定字符集——它的意思是“下一个字符不是字母字符”。这就是您对grep "Files : " | grep -v "Files : [a-zA-Z]" 所做的事情。除了[:alpha:],您还有[:digit:][:xdigit:][:alnum:][:space:][:blank:][:punct:]等。除了匹配的不仅仅是 ASCII 字符之外,它们还可以让您清楚地了解您要匹配的内容(即使它们可以输入更多字符)。
  • 哦,干杯,这很酷。我没想到你可以这样写。你刚刚让我的 grep/sed/awk'ing 分配更容易,所以谢谢你。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-04-12
  • 2018-04-15
  • 1970-01-01
  • 2012-09-19
  • 2014-02-04
  • 1970-01-01
  • 2015-08-08
相关资源
最近更新 更多