単語数を数え、その数を変数に割り当てるよりエレガントな方法はありますか?

単語数を数え、その数を変数に割り当てるよりエレガントな方法はありますか?

スクリプトがあります。

#!/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のようなものを使ってこれらの数を計算して「変更」するよりエレガントな方法はありますか?この場合、ファイルが小さくてあまり問題ではありませんが、ファイルが900 MBの場合、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)強制することです(したがって、変数が設定されていない場合は出力されます)。ブロックを使用してすべての変数を初期値に設定することもできます。awk0BEGIN0

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/範囲選択の使用(これはワイヤー各パターンと数が含まれています。みんなスキーマ)はこの新しい方法よりも倍速です(同じデータについて)。

このように高速化するもう1つの側面(?)の利点は、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 スクリプトは、「count_」で始まる変数を生成するために、新しいシェルコマンドを書式設定します。最後にeval生成されたシェルコマンドは、シェルからインポートされ評価されます。

関連情報