bash +各行のすべての単語数が同じであることを確認する方法

bash +各行のすべての単語数が同じであることを確認する方法

各行のすべての単語/文字列の数が同じであることを確認する方法

各行のすべての単語数が等しい場合、文法はtrueを返し、計算された単語数

行数が異なる場合、構文はfalseを返し、count = NAを返します。

たとえば、次の例では次のようになります。本物そして個数=5

sdb sde sdc sdf sdd
sdc sdb sde sdd sdf
sdb sdc sde sdf sdd
sde sdb sdd sdc sdf
sdc sde sdd sdb sdf

次の例に関連して、我々は得るでしょう間違ったそして個数=NA

sdb sde sdc sdf sdd
sdc sdb sde sdd sdf
sdb sdc sde sdf 
sde sdb sdd sdc sdf
sde sdd sdb sdf

次の例の別の例に関連して、間違ったそして個数=NA

sdb sde sdc sdf sdd
sdc sdb sde sdd sdf
sdb sdc sde sdf 
sde sdb sdd sdc sdf
sde sdd sdb sdf sde 

答え1

使用awk:

awk 'BEGIN { r = "true" } NR == 1 { n = NF; next } NF != n { r = "false"; n = "N/A"; exit } END { printf("status=%s count=%s\n", r, n) }' somefilename

またはawkスクリプトとして:

#!/usr/bin/awk -f

BEGIN { r = "true" }

NR == 1 { n = NF; next }
NF != n { r = "false"; n = "N/A"; exit }

END { printf("status=%s count=%s\n", r, n) }

スクリプトはr「結果」と同じ設定で始まりますtrue(偽ではなく真であると仮定します)。その後、n最初の行のフィールド数で初期化されます(「数字」)。

入力データの他の行に異なる数のフィールドがある場合は、次のように設定され、rスクリプトがfalse終了します(ブロックを介してn)。N/AEND

最後に、rsumの現在の値を印刷します。n


このスクリプトの出力は次のようになります。

status=true count=5

または

status=false count=N/A

これはor export、またはで使用できます。bashdeclareeval

declare $( awk '...' somefilename )

これにより、シェル変数が作成され、count呼び出しstatusシェルで使用できます。

答え2

連想配列を使用して、各数の数量を保持できます。

#!/bin/bash
declare -A seen
while read -a line ; do
    (( seen[${#line[@]}]++ ))
done

if [[ ${#seen[@]} == 1 ]] ; then
    echo count=${#seen[@]}
    exit
else
    echo count=NA
    exit 1
fi

または、外部ツールを使用して操作を実行することもできます。たとえば、次のスクリプトはPerlを使用して-a自動分割オプションを使用して単語数を計算し、sort -u一意の数を取得し、wc -l数が1つ以上あるかどうかを確認します。

#!/bin/bash
out=$(perl -lane 'print scalar @F' | sort -u)
if ((1 == $(wc -l <<<"$out") )) ; then
    echo count=$out
    exit
else
    echo count=NA
    exit 1
fi

答え3

if
  count=$(
    awk 'NR == 1 {print count = NF}
         NF != count {exit 1}' < file
  )
then
  if [ -z "$count" ]; then
    echo "OK? Not OK? file is empty"
  else
    echo "OK all lines have $count words"
  fi
else
  echo >&2 "Not all lines have the same number of words or the file can't be read"
fi

最後の部分から区別できます。その他の数そして開くことができないファイル再び[ -z "$count" ]

答え4

#!/usr/bin/perl

use strict; # get perl to warn us if we try to use an undeclared variable.

# get all words on first line, and store them in a hash
#
# note: it doesn't matter which line we get the word list from because
# we only want to know if all lines have the same number of identical
# words.
my %words = map { $_ => 1 } split (/\s+/,<>);

while(<>) {
  # now do the same for each subsequent line
  my %thisline = map { $_ => 1 } split ;

  # and compare them.  exit with a non-zero exit code if they differ.
  if (%words != %thisline) {
    # optionally print a warning message to STDERR here.
    exit 1;
  }
};

# print the number of words we saw on the first line
print scalar keys %words, "\n";
exit 0

exit 0最後の行は必須ではありません。とにかくデフォルトです。戻りコードがプログラム出力の重要な部分であることを文書化するためにのみ「有用」です。

ノート:1行に繰り返される単語は含まれません。たとえば、次のようにsda sdb sdc sdc sdc計算されます。サム言葉は、いいえ5最後の3つの単語が同じだからです。これが重要な場合は、ハッシュは各単語の発生回数も計算する必要があります。このような:

#!/usr/bin/perl

use strict;   # get perl to warn us if we try to use an undeclared variable.

# get all words on first line, and store them in a hash
#
# note: it doesn't matter which line we get the word list from because
# we only want to know if all lines have the same number of identical
# words.
my %words=();
$words{$_}++ for split (/\s+/,<>);

while(<>) {
  # now do the same for each subsequent line
  my %thisline=();
  $thisline{$_}++ for split;

  # and compare them.  exit with a non-zero exit code if they differ.
  if (%words != %thisline) {
    # optionally print a warning message to STDERR here
    exit 1;
  }
};

# add up the number of times each word was seen  on the first line  
my $count=0;
foreach (keys %words) {
  $count += $words{$_};
};

# print the total
print "$count\n";
exit 0;

重要な違いは、ハッシュ配列がいっぱいになる方法です。最初のバージョンでは、各キー(「単語」)の値を1に設定します。 2 番目のバージョンでは、各キーの発生回数を計算します。

2番目のバージョンも各キーの値を追加する必要があり、表示されているキーの数だけを印刷することはできません。

関連情報