Eu tenho muitos arquivos vcf
HR001.vcf
HR002.vcf
HR003.vcf
HR004.vcf
HR005.vcf
HR006.vcf
HR007.vcf
HR008.vcf
.
.
No10ª colunade CADA arquivo, o cabeçalho da coluna é $i. Em cada arquivo, gostaria de substituir $i pelo nome base dos arquivos. Por exemplo, para o arquivo HR001.vcf, $i=HR001, para HR002.vcf $i=HR002 etc... existe uma maneira simples de fazer isso no Unix. Eu possuo um macbook pro, mas sou novo nisso. Na verdade, esses são arquivos VCF com campos delimitados por tabulações. Sim, cada arquivo possui 236 linhas que devem ser ignoradas. Estou interessado na linha que começa com #CHROM, que é a linha 237 e a coluna 10 dessa linha 237 contém $i
Responder1
Eu usaria perl
:
perl -F'\t' -i -lape '
if ($F[0] eq "#CHROM" && $F[9] eq q($i)) {
$F[9] = ($ARGV =~ s/\.vcf$//r);
$_ = join "\t", @F
}' -- *.vcf
Responder2
Script como este pode fazer o trabalho:
cd /path/to/direcrtory
for i in *.vcf
do
awk '{if (FNR==1) $10=FILENAME; print}' "$i" >"$i.tmp" && mv -f "$i.tmp" "$i"
done
A "mágica" está na variável FILENAME
que awk
contém o nome do arquivo de entrada
Responder3
Responder4
Supondo que seus arquivos sejam delimitados por espaços, isso deve funcionar:
for f_name in HR[0-9]*.vcf; do
awk -v f="${f_name%.*}" 'NR == 1 {$10 = f}1' "$f_name" > "$f_name.tmp"
mv "$f_name.tmp" "$f_name"
done
Faça um loop dentro do diretório e pegue cada vcf
arquivo. Em seguida, remova a extensão do nome do arquivo com ${f_name%.*}
e passe-a como parâmetro para awk
.
awk
usará isso como o nome do arquivo para fazer a substituição.OBSERVAÇÃO: precisa rodar dentro do mesmo diretório do vcf
arquivo, se quiser rodar de outro caminho use o seguinte:
for f_name in /some/full/path/HR[0-9]*.vcf; do
# remove the path
f="${f_name##*/}"
awk -v f="${f%.*}" 'NR == 1 {$10 = f}1' "$f_name" > "$f_name.tmp"
mv "$f_name.tmp" "$f_name"
done
Se os arquivos não forem delimitados por espaços, corrija awk FS
.
EDITAR PARA NOVAS SOLICITAÇÕES E COM BASE NAS MELHORIAS DE @Ed Morton
Estou interessado na linha que começa com #CHROM, que é a linha 237 e a coluna 10 dessa linha 237 contém $i
for f_name in /some/full/path/HR[0-9]*.vcf; do
# remove the path
f="${f_name##*/}"
awk -F'\t' -v f="${f%.*}" 'NR == 237 {$10 = f}1' "$f_name" > "$f_name.tmp" && mv "$f_name.tmp" "$f_name"
done
Esta nova versão dos scripts faz a substituição pelo nome do arquivo apenas no campo que desejar ($10 = f)
e na linha que desejar (NR == 237)
. O awk
parâmetro -F\t
define como awk
ver as linhas e dividi-las em campos.
Mais uma vez obrigado a @Ed Morton que melhorou os scripts originais: Como você pode ver a afirmação: mv "$f_name.tmp" "$f_name"
que é o comando para substituir o arquivo antigo pelo conteúdo do novo (produzido por awk
) é condensado em uma linha: awk '' file > tmp && mv tmp file
desta forma se o awk
o comando falha, a parte direita do &&
não é executada e os dados originais serão mantidos em segurança