Awk
solução:
awk '/empType: /{ f=($2=="A"? 1:0) }f && /ADID: [0-9]+/{ c++ }END{ print c }' file
-
f
- sinalizador indicandoempType: A
processamento da seção -
c
- contagem deempType: A
entradas comADID
chave preenchida
A saída:
2
Eu tenho um arquivo grande com entradas semelhantes a esta:
entry-id: 1
sn: John
cn: Smith
empType: A
ADID: 123456
entry-id: 2
sn: James
cn: Smith
empType: B
ADID: 123456
entry-id: 3
sn: Jobu
cn: Smith
empType: A
ADID: 123456
entry-id: 4
sn: Jobu
cn: Smith
empType: A
ADID:
Cada entrada é separada por uma nova linha. Eu preciso de uma contagem de entradas que tenham um empType de A e também deve ter um valor após o ADID (total de 2). Eu tentei usar awk e grep e egrep, e ainda sem sorte. Alguma idéia?
Awk
solução:
awk '/empType: /{ f=($2=="A"? 1:0) }f && /ADID: [0-9]+/{ c++ }END{ print c }' file
f
- sinalizador indicando empType: A
processamento da seção c
- contagem de empType: A
entradas com ADID
chave preenchida A saída:
2
Aqui está uma solução alternativa do awk que usa a linha em branco ""
como separador de registro RS
e nova linha \n
como separador de campo FS
BEGIN {RS=""; FS="\n"}
{
split($4,a,": ")
split($5,b,": ")
}
a[2]=="A" && b[2]!="" {c++}
END {print c}
o script pode ser executado com
awk -f main.awk file
Método simples two grep
, em que data é o arquivo de entrada:
grep -A1 'empType: A' data | grep -c 'ADID: .\+'
Saída:
2
Gosto da ideia de obter os registros que satisfazem seus requisitos (melhor, por exemplo, para testes) e de contá-los com wc -l
. Então, aqui está um script awk
que faz exatamente isso:
#!/usr/bin/env awk
# getids.awk
BEGIN{
RS="";
FS="\n"
}
/ADID: [0-9]/ && /empType: A/{print $1}
E aqui está em ação:
user@host:~$ awk -f getids.awk data.txt
entry-id: 1
entry-id: 3
user@host:~$ awk -f getids.awk data.txt | wc -l
2
Claro, se você quer apenas a contagem, podemos fazer isso também:
#!/usr/bin/env awk
# count.awk
BEGIN {
RS="";
FS="\n";
count=0;
}
/ADID: [0-9]/ && /empType: A/{count++}
END {
print count
}
E como adoro o Python, aqui está um script Python que faz a mesma coisa:
#!/usr/bin/env python2
# -*- coding: ascii -*-
"""getids.py"""
import sys
# Create a list to store the matched records
records = []
# Iterate over the lines of the input file
with open(sys.argv[1]) as data:
for line in data:
# When an "entry-id" is reached, create a new record
if line.startswith('entry-id'):
entry_id = line.split(':')[1].strip()
records.append({'entry-id': entry_id})
# For other lines, update the current record
elif line.strip():
key = line.partition(':')[0].strip()
value = line.partition(':')[2].strip()
records[-1][key] = value
# Extract the list of records meeting the desired critera
matches = [record for record in records if record['empType'] == 'A' and record['ADID']]
# Print out the entry-ids for all of the matches
for match in matches:
print('entry-id: ' + match['entry-id'])
E aqui está o script Python em ação:
user@host:~$ python getids.py data.txt
entry-id: 1
entry-id: 3
user@host:~$ python getids.py data.txt | wc -l
2
E se realmente queremos apenas as contagens:
#!/usr/bin/env python2
# -*- coding: ascii -*-
"""count.py"""
import sys
# Keep a count of the number of matches
count = 0
# Use flags to keep track of the current record
emptype_flag = False
adid_flag = False
# Iterate over the lines of the input file
with open(sys.argv[1]) as data:
for line in data:
# When an "entry-id" is reached, reset the flags
if line.startswith('entry-id'):
emptype_flag = False
adid_flag = False
elif line.strip() == "empType: A":
emptype_flag = True
elif line.startswith("ADID") and line.strip().split(':')[1]:
adid_flag = True
# If both conditions hold the increment the counter
# and reset the flags
if emptype_flag and adid_flag:
count = count + 1
emptype_flag = False
adid_flag = False
# Print the number of matches
print(count)
E enquanto estamos nisso, que tal um script Bash puro? Aqui está um:
#!/usr/bin/env bash
# getids.bash
while read line; do
if [[ "${line}" =~ "entry-id:" ]]; then
entry_id="${line}"
emptype=false
adid=false
elif [[ "${line}" =~ "empType: A" ]]; then
emptype=true
elif [[ "${line}" =~ ADID:\ [0-9] ]]; then
adid=true
fi
if [[ "${emptype}" == true && "${adid}" == true ]]; then
echo "${entry_id}"
emptype=false
adid=false
fi
done < "$1"
E executando o script bash
:
user@host:~$ bash getids.bash data.txt
entry-id: 1
entry-id: 3
E finalmente, aqui está algo usando apenas grep
e wc
:
user@host:~$ cat data.txt | grep -A1 'empType: A' | grep "ADID: \S" | wc -l
2
Com perl
, isso poderia ser:
perl -l -00ne '
my %f = /(.*?):\s*(.*)/g;
++$n if $f{empType} eq "A" && $f{ADID} ne "";
END {print 0+$n}' < file
-n
faz com que o código dado a -e
seja aplicado a cada registro de entrada -00
para registros serem parágrafos. %f
em que a chave e os valores são mapeados para cada (key):spaces(value)
no registro. $n
quando as condições forem atendidas. $n
no END
(adicionando 0
para garantir que recebemos 0
e não uma string vazia se não houver correspondência). Eu não consegui fazer nada com o -A em um grep, e as outras respostas retornaram o rótulo por muito tempo ou algum outro erro. O que eu achei que funcionou foi
perl -000 -ne 'print if/empType: A/' file.ldif|grep -i -c "^ADID: [0-9A-Za-z]"
Agora eu não sabia o que o perl -000 faz, mas acho que está dizendo pesquisar várias linhas dentro de um parágrafo, -n enquanto loop e uma linha de programa ?? imprimir parágrafo se você encontrar empType: A Agora canalize os parágrafos correspondentes para | grep -i -c "^ ADID:" find ignorar casado e contar o número de ADIDs. Não tenho certeza se os outros comandos falharam por causa da minha versão do Linux, mas o comando acima funcionou muito bem, não sei como tornar o empType um caso ignorado embora ...
Tags command-line linux