$STARTから$ENDまでの行セットをGrepし、$MIDDLEに一致するものを含む

$STARTから$ENDまでの行セットをGrepし、$MIDDLEに一致するものを含む

Grep/Awk/Sed で「0010|」から「0070|」までの行セットを検索し、$PH_NO に一致するものを検索します。

以下はサンプル データです。0012 フィールドにある電話番号と、それに対応する完全な顧客レコード (0010 行目から 0070 行目) を grep 検索する必要があります。1 つのデータ ファイルには、同じ電話番号を持つ 2 つまたは 3 つの顧客レコードが含まれている場合があり、それらすべてを取得する必要があります。

0010|Kumar||57 Rich street|Chennai|Tamil Nadu|
0011|20171115| ID
0012|149 196 222| PH Number 
0013|20161101|20171102|
0022|Payment Method |Lucky customer|
0080|P|5.00-|20161111|Payment|
0080|P|5.00-|20161130|Payment|
0080|TP|10.00-|||
0070|000AYDCHDFF|820|762|
0010|RAM||57 Rich street|Chennai|Tamil Nadu|
0011|20171115| ID
0012|149 196 333| PH Number 
0013|20161101|20171102|
0022|Payment Method |Lucky customer|
0080|P|5.00-|20161111|Payment|
0080|P|5.00-|20161130|Payment|
0080|TP|10.00-|||
0070|000AYDCHDFF|820|762|
0010|Joe||57 Rich street|Chennai|Tamil Nadu|
0011|20171115| ID
0012|149 196 222| PH Number 
0013|20161101|20171102|
0022|Payment Method |Lucky customer|
0080|P|5.00-|20161111|Payment|
0080|P|5.00-|20161130|Payment|
0080|P|5.00-|20161111|Payment|
0080|P|5.00-|20161130|Payment|
0080|P|5.00-|20161111|Payment|
0080|P|5.00-|20161130|Payment|
0080|TP|10.00-|||
0070|000AYDCHDFF|820|762|

注: 私は ksh を搭載した AIX サーバーを使用しています。

答え1

つまり、PH 番号が一致する場合、0010 から 0070 までのレコード全体が必要ですか$PH_NO"? その場合、次のsedワンライナーが機能します:

sed "/^0010/,/^0070/H;/^0010/h;/^0070/! d;x;/|$PH_NO| PH Number/! d"
  • /^0010/,/^0070/H0010から0070までの1つのレコードをホールドスペースに追加する
  • /^0010/h0010は追加されず、新しいレコードが開始されるので、ホールドスペースにコピーします
  • /^0070/! d0070項目でない限り、それ以上の処理や出力は行われません
  • x;/|$PH_NO| PH Number/! d"スペースを交換すると、レコード全体がパターン スペース内に配置され、指定された番号が含まれていない場合は削除されます。

答え2

for r in `grep -n '^0010\|^0012\|^0070' CUSTOMER_FILE | grep -C1 '[0-9]\+:0012|149 196 222|' | grep -o '^[0-9]\+' | paste -d, - - - | sed 's/,[0-9]\+,/,/g'`; do sed -n "$r"p CUSTOMER_FILE; echo; done

149 196 222上記のコマンドの は顧客の電話番号です。調べたい電話番号に変更してください。

CUSTOMER_FILEは検索するファイルです。ファイル名に変更してください。

また、コードをbashスクリプトに入れて、149 196 222を に置き換え$1CUSTOMER_FILEを に置き換えることもできます$2。たとえば、find-customer.shとすると、次のようにスクリプトを実行できます。

./find-customer.sh '149 196 222' your-file-name

このコードの前提条件:

  1. Bash、GNU 環境 (GNU grep、GNU sed)
  2. ファイルは以下の形式に従う必要があります 0010 ... <no 0010 or 0012 or 0070> ... 0012 ... <no 0010 or 0012 or 0070> ... 0070 ... <repeated content as above or end of file>


アップデート

これは高性能バージョンです。(少なくとも上記のオリジナルよりも高性能です。for ループはまったく使用されていません。)

grep -n '^0010\|^0012\|^0070' CUSTOMER_FILE | grep -C1 '[0-9]\+:0012|149 196 222|' | grep -o '^[0-9]\+' | paste -d, - - - | sed -r 's|([0-9]+),[0-9]+,([0-9]+)|\1,\2p;\2a|g' | sed -n -f - CUSTOMER_FILE


AIX のアップデート

質問者は AIX で作業しているため、AIX 上の grep はコンテキスト オプション -A、-B、-C をサポートしていません。

インターネット上には、この問題を解決するために (GNU grep のコンテキスト オプションをシミュレートするために) さまざまな "cgrep" (コンテキスト grep) 実装があります。しかし、それらのほとんどは GNU grep と同じ出力を生成できません。私が見つけた唯一のものは、GNU grep のコンテキスト オプションに最も近いものです。リンクは次のとおりです。https://stackoverflow.com/questions/1685678/advanced-grep-unix/1685782#1685782

この場合に必要な変更をいくつか行いました。

#!/bin/bash
BEFORE=$1
AFTER=$1
FILE=/tmp/.cattmp
PATTERN="$2"
cat > $FILE
for i in $(grep -n "$PATTERN" $FILE | sed -e 's/\:.*//')
  do head -n $(($AFTER+$i)) $FILE | tail -n $(($AFTER+$BEFORE+1))
done
rm $FILE

このファイルを として保存しgrep-context.sh、上記のコマンドのgrep -C1を に置き換えます。./grep-context.sh 1

もう 1 つの確実な方法は、AIX 上で GNU grep をコンパイルすることです (念のため GNU sed もコンパイルしてください)。

答え3

次のスクリプトを使用できます:

#!/bin/sh
read START
read END
read MATCH

REND=$(grep -n "$END" lines | tail -1 | cut -d":" -f 1)
RSTART=$(grep -n "$START" lines | head -1 | cut -d":" -f 1)

sed $RSTART,$REND!d lines | grep "$MATCH"

それをファイルに入れて、このコマンドで実行権限を追加します

chmod +x script.sh

START変数:開始ライン番号(例:0010)

END変数:終了変数(例:0070)

MATCH変数:行内で探している単語/文字/数字(例:0012)

RSTART変数:テキストファイル内の開始行番号(例:1)

REND変数:テキストファイル内の開始行番号(例:32)


編集:

最後の行を次のように変更すると、行が何回繰り返されたかを確認することもできます。

sed $RSTART,$REND!d lines | grep "$MATCH" | sort | uniq -c

関連情報