Com awk
, verificando se a quarta coluna está no formato correto:
awk 'match($4, /^[0-9]+\/[0-9]+:/) {
c = substr($4, RSTART, RLENGTH-1)
if (!seen[c]++) print c
}'
Eu não sei o que eu tenho no meu enorme arquivo vcf.gz que se parece com isso
CHROM POS ALT 12345
1 345632 T 0/1:4,4:8:99:105,0,106
4 032184 C 1/1:46,9:55:99:99,0,1222
6 843290 A 0/1:67,20:87:99:336,0,1641
7 743290 C 0/1:37,20:57:99:336,0,2641
8 329283 T 0/2:99:21:253,0,290:11,10
9 789320 C 2/2:99:21:253,0,290:11,10
Eu gostaria de extrair todos os valores exclusivos na 4ª coluna antes do ":". Isso é neste caso:
0/1
1/1
0/2
2/2
Você tem alguma sugestão?
Com awk
, verificando se a quarta coluna está no formato correto:
awk 'match($4, /^[0-9]+\/[0-9]+:/) {
c = substr($4, RSTART, RLENGTH-1)
if (!seen[c]++) print c
}'
Vamos supor que as linhas que começam com uma letra sejam comentários ou sejam ignoradas.
zcat vcf.gz | awk \
'BEGIN {
RS = "[\t\v\f ]*(\r\n|\n\r|\r|\n)" ;
FS = "[\t\v\f ]+"
}
/^[A-Za-z]/ {
next
}
NF >= 4 {
key = $4 ;
sub(/:.*$/, "", key) ;
seen[key]++
}
END {
for (key in seen)
printf "%s\n", key
}'
Você pode escrever o comando inteiro em uma linha (remova o \
no final da primeira linha, por exemplo), porque eu adicionei todos os pontos-e-vírgulas necessários para fazer isso.
A regra BEGIN
configura o suporte universal de nova linha. Todos os espaços em branco no final das linhas são ignorados, e qualquer formulário de nova linha (CR, LF, CRLF, LFCR) é aceito como uma nova linha. Qualquer número de tabulações ou espaços são tratados como separadores de campos.
A regra /^[A-Za-z]/
se aplica a todas as linhas que começam com uma letra. O next
faz com que eles sejam ignorados.
A próxima regra se aplica a todos os registros (linhas) com pelo menos quatro campos. O quarto campo é copiado para a variável key
, então tudo após os primeiros dois pontos (incluindo os dois pontos) é removido. Usamos o valor resultante como uma chave para o array associativo seen
. O valor que atribuímos não importa realmente, mas aqui, seen[key]
conterá o número de vezes que cada valor foi referido (1 ou mais).
A regra END
é executada após toda a entrada ter sido processada. Aqui, o loop itera sobre as chaves de seen[]
array (em uma ordem não especificada) e apenas imprime as chaves.
Se você quiser manter o pedido nos dados ou usar uma ordem específica para as chaves, o snippet acima precisa de pequenas modificações.
Se perl
estiver bem:
$ perl -lane '($k) = $F[3] =~ m/^([^:]+)/; print $k if !$seen{$k}++ && $. > 1' ip.txt
0/1
1/1
0/2
2/2
($k) = $F[3] =~ m/^([^:]+)/
get string antes de :
da quarta coluna
Se o padrão antes de :
tiver que ser necessariamente do padrão digits/digits
, altere a correspondência para m|^(\d+/\d+):|
Como um one-liner
gzip -dc input.gz | grep -E "^[0-9]" | cut -f 1 -d : | sort -k 4 -u | awk ' { print $4 } '
Explicação:
* gzip -dc # decompress and write to standard output
* grep -E "^[0-9]" # only look at lines starting with a digit
* cut -f 1 -d: # remove the text following the colon
* sort -k4 -u # sort on the forth field - uniquely
* awk ' { print $4 } ' # print the fourth field (that we sorted on)
Eu usaria:
grep -o -P '.{1}/.{1}' file
No seu caso:
zcat vcf.gz | grep -o -P '.{1}/.{1}'
Editar: para apenas uma ocorrência, adicione uniq no final da linha:
zcat vcf.gz | grep -o -P './.' | uniq
ou se você quiser em ordem:
zcat vcf.gz | grep -o -P './.' | sort -u
Tags text-processing awk filter