
Gostaria de extrair colunas delimitadas por tabulações de um arquivo de texto ("columns.txt") no qual o cabeçalho (primeira linha) corresponde a determinadas strings listadas em outro arquivo de texto ("strings.txt").
"colunas.txt" tem esta aparência:
rs2438689 rs54666437 rs9877702046 rs025436779...
0 0 0 1
1 1 2 2
0 1 2 0
... ... ... ...
"strings.txt" fica assim:
rs2438689
rs9877702046
...
O arquivo de texto de saída "output.txt" deve ser semelhante a este (delimitado por tabulações):
rs2438689 rs9877702046...
0 0
1 2
0 2
... ...
Alguma sugestão sobre como fazer isso com o awk? Obrigado!
Responder1
Em vez de Awk, que tal criar uma lista separada por vírgulas de nomes de colunas de strings.txt
e usá-la como uma lista de namedcol
s para csvtool
:
$ csvtool -t TAB -u TAB namedcol "$(paste -sd, < strings.txt)" columns.txt
rs2438689 rs9877702046
0 0
1 2
0 2
... ...
ou da mesma forma com csvcut/csvformat
o baseado em Python csvkit
:
$ csvcut -tc "$(paste -sd, < strings.txt)" columns.txt | csvformat -T
rs2438689 rs9877702046
0 0
1 2
0 2
... ...
Responder2
Comperl
$ perl -F'\t' -lane 'if(!$#ARGV){ $h{$_}=1 }
else{ @i = grep { $h{$F[$_]} == 1 } 0..$#F if !$c++;
print join "\t", @F[@i]}' strings.txt columns.txt
rs2438689 rs9877702046
0 0
1 2
0 2
if(!$#ARGV){ $h{$_}=1 }
para o primeiro arquivo de entrada, crie um hash com o conteúdo da linha como chave@i = grep { $h{$F[$_]} == 1 } 0..$#F if !$c++
para a primeira linha do segundo arquivo, crie uma lista de índice de todos os nomes de colunas correspondentes do hashprint join "\t", @F[@i]
imprima as colunas correspondentes
Responder3
Modificandominha solução para sua pergunta anterior:
awk -F '\t' -f script.awk strings.txt columns.txt
Onde script.awk
é
BEGIN { OFS = FS }
FNR == NR {
columns[$1] = 1
next
}
FNR == 1 {
for (i = 1; i <= NF; ++i)
if ($i in columns)
keep[i] = 1
}
{
nf = split($0, fields, FS)
$0 = ""
j = 0
for (i = 1; i <= nf; ++i)
if (i in keep)
$(++j) = fields[i]
print
}
Aqui, o FNR == NR
bloco só seria executado durante a leitura do primeiro arquivo listado na linha de comando ( strings.txt
). Ele preencheria a columns
matriz com chaves que são os nomes das colunas. O resto do código émais ou menosinalterado em relação à solução antiga, exceto o formulário onde verificamos se a coluna atual é aquela que gostaríamos de manter (no FNR == 1
bloco).
Abordando operguntas nos comentários:
Para sempre copiar as primeiras seis colunas e cortar os cabeçalhos das colunas em _
, altere
FNR == 1 {
for (i = 1; i <= NF; ++i)
if ($i in columns)
keep[i] = 1
}
em
FNR == 1 {
for (i = 1; i <= NF; ++i) {
sub("_.*", "", $i)
if (i <= 6 || $i in columns)
keep[i] = 1
}
}
Responder4
Feito usando o script abaixo, pode demorar muito para funcionar bem
k =wc -l file1| awk '{print $1}'
for ((i=1;i<=$k;i++)); do for j in `cat file2`; do awk -v i="$i" -v j="$j" '$i == j {x=NR+k}(NR<=x){print $i}' file1; done ; done>final.txt
z=`wc -l final.txt| awk '{print $1}'`
for ((i=1;i<=$z;i++)); do j=$(($i+3)); sed -n ''$i','$j'p' final.txt >file_starting_with_$i.txt; i=$j; done
paste file_starting_with*
saída
rs2438689 rs9877702046
0 0
1 2
0 2