是否有更优雅的方法来计算单词数并将该计数分配给变量?

是否有更优雅的方法来计算单词数并将该计数分配给变量?

我有一个脚本:

#!/bin/bash

/root/xiotech status > xiostatus.tmp
SyncCount=$(grep -c Sync xiostatus.tmp)
PauseCount=$(grep -c paused xiostatus.tmp)
CopyingCount=$(grep -c Copying xiostatus.tmp)

if [ "$SyncCount" -eq "11" ]
then echo All 11 mirrors are in sync.

else echo $PauseCount mirrors are paused and $CopyingCount mirrors are syncing.
fi

rm -f xiostatus.tmp

有没有更优雅的方法来使用 awk 之类的东西来计数和“可变化”这些计数?在这种情况下,文件很小,所以没什么大不了的,但如果文件是 900mb,则需要很多额外的周期来浏览它 3 次......

答案1

awk可以很容易地替换整个脚本:

#!/usr/bin/awk -f

/Sync/ {SyncCount++}
/paused/ {PauseCount++}
/Copying/ {CopyingCount++}

END {
    if(SyncCount == 11)
        print "All 11 mirrors are in sync."
    else
        print (+PauseCount) " mirrors are paused and " (+CopyingCount) " mirrors are syncing."
}

(+var)强制awk将变量视为数字(因此0如果变量未设置,它将输出)。您还可以使用BEGIN块将所有变量设置为0初始值:

BEGIN {
    SyncCount = PauseCount = CopyingCount = 0
}

将其保存在文件中并运行awk -f /path/to/the/script.awk xiostatus.tmp。如果您不需要临时文件,您甚至可以这样做/root/xiotech status | awk -f /path/to/the/script.awk

如果您在脚本上设置执行位awk,则可以将其作为独立可执行文件调用:/path/to/the/script.awk xiostatus.tmp、 或/root/xiotech status | /path/to/the/script.awk

答案2

对于那些想要数数的人全部实例,这是一个 awk 版本,它将计数多种的 不重叠当同一行有多个时的情况

更新:我现在已经包含了另一种使用split(....这是 很多match( substr(...比现在在更快的方法下面列出的方法更快。该split(...方法比其他方法快 4 倍以上...(在 87 个文件上测试,总共 407,612 行。
为了进一步比较,迈克尔·莫罗泽克方法,使用/Sync/范围选择(这算线包含每个模式与计数全部模式的实例)的速度是这个新方法的两倍(对于相同的数据)。

这种更快的另一个附带(?)好处split(methos)是它对文件中无效的 UTF-8 字符相当宽容(只要它们不在分隔符模式中)...分隔符它们本身就是被计算的实际字符串模式...我的几个测试文件中包含无效的 UTF-8,我花了很长时间才发现为什么我从这两种方法中得到了不同的结果。
一旦问题文件被重新编码为有效的 UTF-8,两种方法都会产生相同的结果。

这是新的更快的方法(快 4 倍以上)...使用split(...

#!/bin/bash
pat='xx|yy|zz'
awk -v vpat="$pat" 'BEGIN { 
  split(vpat, pat, "|"); for(i in pat) pz++ 
} 
{ if (NF) { for( p in pat ) { ct[p]+=(split( $0, A, pat[p] ) -1) }}
}
END { print " count   pattern"
      for (p=1; p<=pz; p++) { printf "%6d   %s\n", +ct[p], pat[p] } 
}' file

这是较慢的方法。使用match( substr(...

#!/bin/bash
# Count occurrences of multiple non-overlapping string patterns
awk 'BEGIN {
  pattern[1]="xx"
  pattern[2]="yy"
  pattern[3]="zz"
}
{ for( p in pattern ) {
    LHB=0; RSTART=RLENGTH=1
    while( match( substr( $0, LHB+=(RSTART+RLENGTH-1)), pattern[p] )){
      count[p]++ 
    }
  }
} END {
  print "occurs  pattern"
  for (p in pattern) {
    printf "%6d  %s\n", +count[p], pattern[p] 
  } 
}' file

这是输入文件

xx xx  xx
xx             yy           xx

输出如下:

occurs  pattern
     5  xx
     1  yy
     0  zz

答案3

怎么样:

eval `/root/xiotech status | grep -Eo 'Sync|paused|Copying' | sort | uniq -c | 
    awk '{print "count_" $2 "=" $1}'`
if [ "$count_Sync" -eq 11 ]; then
    echo All 11 mirrors are in sync.
else
    echo $count_paused mirrors are paused and $count_Copying mirrors are syncing.
fi

允许grep -Eo搜索多个模式(用“|”分隔)并仅返回匹配的字符串。显示sort | uniq -c找到的单词数。 awk 脚本格式化新的 shell 命令以创建以“count_”开头的变量。最后,eval将获取创建的 shell 命令并在 shell 中评估它们。

相关内容