Usando awk
, a esta tabela quero adicionar uma coluna onde a primeira linha é "INFO" e o restante das linhas são todas "1".
$ gunzip -c foo.gz | head
SNPID CHR BP Allele1 Allele2 Freq1 Effect StdErr P.value TotalN
rs1000033 1 226580387 t g 0.8266 -0.0574 0.0348 0.09867 17310
rs1000050 1 162736463 t c 0.8545 0.0654 0.0461 0.1564 10864
onde
gunzip -c foo.gz | head | cat -A
SNPID^ICHR^IBP^IAllele1^IAllele2^IFreq1^IEffect^IStdErr^IP.value^ITotalN^M$
rs1000033^I1^I226580387^It^Ig^I0.8266^I-0.0574^I0.0348^I0.09867^I17310^M$
rs1000050^I1^I162736463^It^Ic^I0.8545^I0.0654^I0.0461^I0.1564^I10864^M$
Como é um .gz
arquivo que usei
gunzip -c foo.gz | \
awk 'BEGIN {FS="\t"; OFS="\t"} NR == 1 {print $0 OFS "INFO"} NR > 1 {print $0 OFS "1"}' | \
gzip > foo.V2.gz
Por alguma razão, isso parece mudar o nome da coluna, mas não a coluna esperada no final.
$ gunzip -c foo.V2.gz | head
SNPID INFO BP Allele1 Allele2 Freq1 Effect StdErr P.value TotalN
--------^
rs1000031 1 226580387 t g 0.8266 -0.0574 0.0348 0.09867 17310
rs1000051 1 162736463 t c 0.8545 0.0654 0.0461 0.1564 10864
Estranhamente, quando eu cat -A
faço isso, a coluna parece estar onde deveria estar.
$ gunzip -c foo.V2.gz | head | cat -A
SNPID^ICHR^IBP^IAllele1^IAllele2^IFreq1^IEffect^IStdErr^IP.value^ITotalN^M^IINFO$
----------------------------------------------------------------------------^
rs1000033^I1^I226580387^It^Ig^I0.8266^I-0.0574^I0.0348^I0.09867^I17310^M^I1$
rs1000050^I1^I162736463^It^Ic^I0.8545^I0.0654^I0.0461^I0.1564^I10864^M^I1$
Eu gostaria de saber,
- O que está acontecendo aqui?
- posso confiar
gunzip -c foo.V2.gz | head
ougunzip -c foo.V2.gz | head | cat -A
agora?? - como obter minha saída esperada usando
gunzip -c foo.V2.gz | head
SNPID CHR BP Allele1 Allele2 Freq1 Effect StdErr P.value TotalN INFO
rs1000033 1 226580387 t g 0.8266 -0.0574 0.0348 0.09867 17310 1
rs1000050 1 162736463 t c 0.8545 0.0654 0.0461 0.1564 10864 1
Observe que estou usando um script de configuração que define SNPID=1; CHR=2; ...
onde estou, dependendo dos números das colunas que estou especificando como corretos para as análises subsequentes.
Como já mencionado, você tem finais de linha do DOS. Veja por que minha saída de ferramenta se sobrescreve e como faço para consertar para obter uma descrição do problema e possíveis soluções, por exemplo, usando qualquer awk:
Você poderia usar
RS="\r\n"
, mas um RS multi-char é uma extensão GNU awk que foi recentemente adotada por 1 ou 2 outras variantes do awk. Com qualquer outra configuração awk compatível com POSIXRS="\r\n"
será tratada da mesma forma que se você definir,RS="\r"
pois por POSIXRS
só pode haver um único caractere literal. Ele também falhará em sistemas onde os primitivos C subjacentes retiram o\r
final das linhas antes que o awk os veja, portantoRS="\r?\n"
é um pouco mais robusto. Com qualquer awk você pode deixarRS
como valor padrão\n
e adicionar{sub(\r$/,"")}
como a primeira instrução do script.Eu também arrumei algumas outras coisas em seu script, por exemplo, removendo as variáveis de configuração de código que você não precisa ou que já possui esse valor, alterando suas 2 instruções de impressão para 1, usando OFS conforme projetado e livrando-me dos escapes desnecessários no final das linhas após um símbolo de barra vertical.
Sua entrada parece ser algum tipo de arquivo TSV com finais de linha da Microsoft.
Então você poderia usar
mlr
em vez dissoawk
suporta 2 tipos de tsv e pode especificar o delimitador de registro.--tsv
v
valores sãot
abs
eparados, mas\\
,\t
,\r
,\n
pode ser usado para incorporar\
caracteres , TAB, CR e LF nos campos.--tsvlite
v
valores sãot
abparadoss
e não é possível incorporar delimitadores de linha ou tabulações nos valores dos campos.Aqui, como você deseja apenas adicionar uma coluna extra sem cabeçalho nem valores contendo nenhum desses caracteres, usar um ou outro não fará diferença.
Por padrão,
mlr
aceita delimitadores de linha CRLF (Microsoft) ou LF (Unix) e gera linhas delimitadas com LF (Unix). Mas você pode passar--rs crlf
para linhas de saída delimitadas com CRLF (Microsoft).Então:
Para obter um tsv Unix na saída e aceitar tsv Microsoft ou Unix na entrada.
Para obter um tsv da Microsoft na saída e aceitar tsv da Microsoft ou Unix na entrada.
Desde a versão 6.0.0,
mlr
possui suporte integrado para leitura de arquivos compactados com gzip, então você também pode fazer:(passe a
--gzin
opção se o caminho do arquivo não terminar em.gz
).mlr
(miller, geralmente enviado emmiller
pacote ) é uma ferramenta especializada no processamento de dados tabulares. Pode levar vários verbos como argumento para diferentes ações a serem executadas nos registros, comosort
,cut
,join
,filter
...put
é aquele usado para fazer modificações nos registros usando uma linguagem simples de domínio específico , não totalmente diferente da deawk
.Nessa linguagem, como em
awk
,$
é usado para fazer referência a campos nos registros , exceto que esses campos são nomeados ¹. Com$INFO = 1
, damos aoINFO
campo um valor numérico² de1
para cada registro. Se esse campo ainda não existir, ele será adicionado e aparecerá como uma coluna extra.¹ embora também possa ser numerado como ao processar csv/tsv sem cabeçalho com
--implicit-csv-header
.² você usaria
$INFO = "1"
para defini-lo como uma string, o que seria diferente para formatos de saída como JSON, mas não para tsv, onde não há indicação de tipo.Como @steeldriver observou nos comentários, o arquivo parecia ser do Windows contaminado com caracteres de retorno de carro (CR) e alimentação de linha (LF), podemos remover a configuração de separadores de registro,
RS="\r\n"
masORS="\n"
para não reintroduzir o mesmo problema.Para adicionar
<tab>INFO
na primeira linha ou<tab>1
nas linhas subsequentes logo antes do delimitador de linha, se esse delimitador de linha é LF (Unix) ou CR seguido de LF (Microsoft), você pode fazer:Para editar o arquivo no local, em teoria você poderá usar a
-i
opção junto com aPerlIO::gzip
camada IO (pode precisar ser instalada separadamente):Embora eu ache isso com minha versão, ela falha com Can't do inplace edit on foo.gz: Cannot make temp name: Inappropriate ioctl for device. o que parece um bug para mim.