![Grep 尋找從 $START 到 $END 並且在 $MIDDLE 中包含匹配項的一組行](https://rvso.com/image/122435/Grep%20%E5%B0%8B%E6%89%BE%E5%BE%9E%20%24START%20%E5%88%B0%20%24END%20%E4%B8%A6%E4%B8%94%E5%9C%A8%20%24MIDDLE%20%E4%B8%AD%E5%8C%85%E5%90%AB%E5%8C%B9%E9%85%8D%E9%A0%85%E7%9A%84%E4%B8%80%E7%B5%84%E8%A1%8C.png)
Grep/Awk/Sed 用於尋找「0010|」中的一組行至“0070|” AND 包含 $PH_NO 中的符合項
以下是範例資料。我需要 grep 查找 0012 欄位中出現的電話號碼以及相應的完整客戶記錄(從 0010 到 0070 的行)。
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
oneliner 就可以工作了:
sed "/^0010/,/^0070/H;/^0010/h;/^0070/! d;x;/|$PH_NO| PH Number/! d"
/^0010/,/^0070/H
將 0010 到 0070 之間的一筆記錄追加到保留空間/^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。
在網路上,有多種「cgrep」(上下文grep)實作來解決這個問題(模擬GNU 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
上面我的命令中的內容。
我認為一勞永逸的另一種方法是在 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
啟動變數:您的起始行號(例如 0010)
結束變數:您的結束變數(例如 0070)
匹配變數:您在一行中查找的單字/字元/數字(例如 0012)
RSTART 變數:文字檔案中的起始行號(例如1)
撕裂變數:文字檔案中的起始行號(例如 32)
編輯:
您還可以將最後一行更改為以下內容來查看一行重複了多少次:
sed $RSTART,$REND!d lines | grep "$MATCH" | sort | uniq -c