![$STARTから$ENDまでの行セットをGrepし、$MIDDLEに一致するものを含む](https://rvso.com/image/122435/%24START%E3%81%8B%E3%82%89%24END%E3%81%BE%E3%81%A7%E3%81%AE%E8%A1%8C%E3%82%BB%E3%83%83%E3%83%88%E3%82%92Grep%E3%81%97%E3%80%81%24MIDDLE%E3%81%AB%E4%B8%80%E8%87%B4%E3%81%99%E3%82%8B%E3%82%82%E3%81%AE%E3%82%92%E5%90%AB%E3%82%80.png)
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/H
0010から0070までの1つのレコードをホールドスペースに追加する/^0010/h
0010は追加されず、新しいレコードが開始されるので、ホールドスペースにコピーします/^0070/! d
0070項目でない限り、それ以上の処理や出力は行われません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
を に置き換え$1
、CUSTOMER_FILE
を に置き換えることもできます$2
。たとえば、find-customer.shとすると、次のようにスクリプトを実行できます。
./find-customer.sh '149 196 222' your-file-name
このコードの前提条件:
- Bash、GNU 環境 (GNU grep、GNU sed)
- ファイルは以下の形式に従う必要があります
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