Grep 尋找從 $START 到 $END 並且在 $MIDDLE 中包含匹配項的一組行

Grep 尋找從 $START 到 $END 並且在 $MIDDLE 中包含匹配項的一組行

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"嗎?然後這個sedoneliner 就可以工作了:

sed "/^0010/,/^0070/H;/^0010/h;/^0070/! d;x;/|$PH_NO| PH Number/! d"
  • /^0010/,/^0070/H將 0010 到 0070 之間的一筆記錄追加到保留空間
  • /^0010/h0010 不應被附加,而是開始一個新記錄,因此將其複製到保留空間
  • /^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

這段程式碼的前提條件:

  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。

在網路上,有多種「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

相關內容