BASHの3行と2行の比較

BASHの3行と2行の比較

次のテキストファイルがあります。

2014-11-24 12:59:42.169 101.0.0.0 source
2014-11-24 12:59:40.375 104.156.80.0 destination
2014-11-24 12:59:36.729 104.219.48.0 destination
2014-11-24 12:59:40.377 104.37.160.0 source
2014-11-24 12:58:58.902 107.188.128.0 both
2014-11-24 12:59:06.456 107.188.128.0 source
2014-11-24 12:59:06.840 107.192.0.0 both
2014-11-24 12:59:42.043 107.192.0.0 destination
2014-11-24 12:58:58.904 107.192.0.0 source
2014-11-24 12:59:55.488 111.0.0.0 both
2014-11-24 12:59:30.007 111.0.0.0 destination
2014-11-24 12:59:33.209 108.175.32.0 destination
2014-11-24 12:59:06.841 108.175.32.0 source
  • IP 107.188.128.0の場合、タグは次のとおりです。両方とソース、ちょうど次のように表示したいと思います。両方
  • IP 107.192.0.0の場合、タグは次のとおりです。ターゲットとソースの両方、ちょうど次のように表示したいと思います。両方
  • IP 111.0.0.0の場合、タグは次のとおりです。両方と目的地、ちょうど次のように表示したいと思います。両方
  • IP 107.192.0.0の場合、タグは次のとおりです。目的地とソース、ちょうど次のように表示したいと思います。両方

私が望む出力は次のようになります。

2014-11-24 12:59:42.169 101.0.0.0 source
2014-11-24 12:59:40.375 104.156.80.0 destination
2014-11-24 12:59:36.729 104.219.48.0 destination
2014-11-24 12:59:40.377 104.37.160.0 source
2014-11-24 12:59:06.456 107.188.128.0 both
2014-11-24 12:59:42.043 107.192.0.0 both
2014-11-24 12:59:55.488 111.0.0.0 both
2014-11-24 12:59:33.209 108.175.32.0 both

IPに一致する最新の日時を出力します。

私が試したことは次のとおりです。

awk '{print $3}' input.txt | sort -u | while read line

do 
grep $line input.txt | head -1 
done

ただし、IP 108.175.32.0では機能しません。

このソリューションは次のとおりです。

  sed '
      N
      s/\([0-9.]\)\s\S\+\n.*\1\s\S\+$/\1 both/
      t
      P
      D
      ' input.txt

しかし、これは効果があります。ただ108.175.32.0へ。

awk一度に希望の出力を使用または取得できますかsed?私はこの時点で詰まった。

答え1

この質問は次のようになります。ここ若干修正済み:

| sed '
    :1
    N    #add next line
    s/\([0-9.]\+\)\s\S\+\n.*\s\1\s\S\+$/\1 both/
    t1   #go to point 1 if exchange took place
    P    #print first line from two
    D    #remove first line, return to start
    '

答え2

あなたの要件を満たしていますか?

 awk 'BEGIN{ip="nothing" 
    time=""
    type=""
 }
 {
    # if the currently processed ip is not the same as the line 
    # being processed then we need to print the data.
    if (ip != $3)
    {
       # if ip == nothing then this is the first line do not print.
       # otherwise we are at a line with a new ip and we should print
       # the data saved from previous lines.
       if(ip != "nothing")
       { 
          print time, ip, type
       }
    # Remove the time update line since we are now doing it outside the
    # if statement so it always updates the time. This will make the 
    # outputted line print the last time stamp for each IP.
    #time=$1" "$2
    ip=$3
    type=$4
    }
    else if (type != $4)
    {
       type="both"
    }
    # no matter what update the time stamp value so that the latest
    # time stamp is kept for any given ip. Putting it after the if
    # that handles when a new ip is found, makes sure that it does not
    # override the value printed for the old ip line.
    time=$1" "$2
 }
 END{
    # Once we reach the end of the input, we still have 
    # the last set of values to print.
    print time, ip, type
 }'

ファイルを読み取り、IPが同じでタイプ(des、src、両方)が異なる2つの連続した行がある場合は、タイプを両方に変更し、そうでない場合は、データに新しいIPが見つかった場合に印刷するタイプになります。それは...

答え3

与えられた入力ファイルfoo.txt:

  1. sort最初の3つのフィールドの数、
  2. 使用datamashIPタグの結合操作を実際に完了し、
  3. cut重複フィールド、
  4. その後、sed組み合わせタグを「すべて」に置き換えます。

    sort -r -k1n -k2n -k3n foo.txt | \
      datamash -W -f -s -g3 collapse 4 | \
      cut --complement -f4 | \
      sed 's/\t[sdb].*,.*$/\tboth/g'
    

出力:

2014-11-24  12:59:42.169    101.0.0.0       source
2014-11-24  12:59:40.375    104.156.80.0    destination
2014-11-24  12:59:36.729    104.219.48.0    destination
2014-11-24  12:59:40.377    104.37.160.0    source
2014-11-24  12:59:06.456    107.188.128.0   both
2014-11-24  12:59:42.043    107.192.0.0     both
2014-11-24  12:59:33.209    108.175.32.0    both
2014-11-24  12:59:55.488    111.0.0.0       both

答え4

OPで提供されたコードを修正しました。

awk '{print $3}' input.txt | sort -u | while read line
do 
    echo -n `grep $line input.txt | \
      sort -r | head -1 | \
      grep -oe "[^a-z]*"` ' ' # print latest time stamp
    if [[ $(grep -c $line input.txt) -ge 2 ]];  then 
        echo  'both'
    else
        echo `grep $line input.txt | grep -oe "[a-z]*"`
    fi
done

出力:

2014-11-24 12:59:42.169 101.0.0.0  source
2014-11-24 12:59:40.375 104.156.80.0  destination
2014-11-24 12:59:36.729 104.219.48.0  destination
2014-11-24 12:59:40.377 104.37.160.0  source
2014-11-24 12:59:06.456 107.188.128.0  both
2014-11-24 12:59:42.043 107.192.0.0  both
2014-11-24 12:59:33.209 108.175.32.0  both
2014-11-24 12:59:55.488 111.0.0.0  both

関連情報