![Grep para um conjunto de linhas de $START a $END AND que contém uma correspondência no $MIDDLE](https://rvso.com/image/122435/Grep%20para%20um%20conjunto%20de%20linhas%20de%20%24START%20a%20%24END%20AND%20que%20cont%C3%A9m%20uma%20correspond%C3%AAncia%20no%20%24MIDDLE.png)
Grep/Awk/Sed para um conjunto de linhas de "0010|" para "0070|" E que contém uma correspondência no $PH_NO
Abaixo estão os dados de amostra. Preciso usar o grep para o número de telefone que está presente no campo 0012 e os registros completos do cliente correspondentes, linhas de 0010 a 0070. Um arquivo de dados pode conter dois ou três registros de clientes com o mesmo número de telefone e preciso obter todos eles.
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|
Nota: estou em um servidor AIX com ksh.
Responder1
Então você quer o registro completo de 0010 a 0070, se o número PH corresponder $PH_NO"
? Então este sed
oneliner funcionará:
sed "/^0010/,/^0070/H;/^0010/h;/^0070/! d;x;/|$PH_NO| PH Number/! d"
/^0010/,/^0070/H
para anexar um registro de 0010 a 0070 ao espaço de espera/^0010/h
o 0010 não deve ser anexado, mas iniciar um novo registro, então copie-o para o espaço de espera/^0070/! d
nenhum processamento ou saída adicional, a menos que seja o item 0070x;/|$PH_NO| PH Number/! d"
troque os espaços, para que todo o registro fique no espaço padrão agora e exclua-o se não contiver o referido número.
Responder2
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
no comando acima está o número de telefone do cliente. Mude para o número de telefone que você deseja descobrir.
CUSTOMER_FILE
é o arquivo que você deseja pesquisar. Mude para o nome do seu arquivo.
Você também pode colocar o código em um script bash e substituir 149 196 222
por . Diga find-customer.sh, então você pode executar o script assim$1
CUSTOMER_FILE
$2
./find-customer.sh '149 196 222' your-file-name
Pré-requisito deste trecho de código:
- Bash, ambiente GNU (GNU grep, GNU sed)
- Seu arquivo deve seguir o formato abaixo
0010 ... <no 0010 or 0012 or 0070> ... 0012 ... <no 0010 or 0012 or 0070> ... 0070 ... <repeated content as above or end of file>
ATUALIZAR
Esta é uma versão de alto desempenho. (Pelo menos maior que o original acima. Nenhum loop for envolvido.)
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
ATUALIZAÇÃO para AIX
Já que o solicitante está trabalhando no AIX. O grep no AIX não suporta opções de contexto, -A, -B, -C.
Na Internet, há uma variedade de implementações "cgrep" (context grep) para resolver este problema (para simular a opção de contexto GNU grep). Mas a maioria deles não pode fornecer a mesma saída que o GNU grep. Apenas um que encontrei é o mais próximo da opção de contexto GNU grep. A ligação éhttps://stackoverflow.com/questions/1685678/advanced-grep-unix/1685782#1685782
Fiz algumas modificações necessárias para este caso.
#!/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
Salve este arquivo como grep-context.sh
e substitua -o grep -C1
no ./grep-context.sh 1
meu comando acima.
Outra maneira que penso ser de uma vez por todas é compilar o GNU grep no AIX. (também compile GNU sed apenas por precaução)
Responder3
Você pode usar este script:
#!/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"
Coloque-o em um arquivo e adicione a permissão de execução com este comando
chmod +x script.sh
Variável INICIAR:Seu número de linha inicial (por exemplo, 0010)
Variável FIM:Sua variável final (por exemplo, 0070)
Variável CORRESPONDÊNCIA:A palavra/caractere/número que você está procurando em uma linha (por exemplo, 0012)
Variável RSTART:O número da linha inicial no arquivo de texto (por exemplo, 1)
Variável REND:O número da linha inicial no arquivo de texto (por exemplo, 32)
EDITAR:
Você também pode ver quantas vezes uma linha se repetiu, alterando a última linha para isto:
sed $RSTART,$REND!d lines | grep "$MATCH" | sort | uniq -c