Substitua o cabeçalho de uma determinada coluna pelo nome do arquivo

Substitua o cabeçalho de uma determinada coluna pelo nome do arquivo

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 FILENAMEque awkcontém o nome do arquivo de entrada

Responder3

insira a descrição da imagem aqui@YetAnotherUser, veja uma imagem do arquivo de amostra referente à minha solicitação: "Substitua o cabeçalho de uma determinada coluna pelo nome do arquivo"

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 vcfarquivo. Em seguida, remova a extensão do nome do arquivo com ${f_name%.*}e passe-a como parâmetro para awk.

awkusará isso como o nome do arquivo para fazer a substituição.OBSERVAÇÃO: precisa rodar dentro do mesmo diretório do vcfarquivo, 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 awkparâmetro -F\tdefine como awkver 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 filedesta forma se o awko comando falha, a parte direita do && não é executada e os dados originais serão mantidos em segurança

informação relacionada