Reemplazar el encabezado de una columna determinada con el nombre del archivo

Reemplazar el encabezado de una columna determinada con el nombre del archivo

tengo muchos archivos vcf

HR001.vcf
HR002.vcf
HR003.vcf
HR004.vcf
HR005.vcf
HR006.vcf
HR007.vcf
HR008.vcf
.
.

En eldécima columnade CADA archivo, el encabezado de la columna es $i. En cada archivo, me gustaría reemplazar $i con el nombre base de los archivos. Por ejemplo, para el archivo HR001.vcf, $i=HR001, para HR002.vcf $i=HR002, etc., ¿existe una manera sencilla de hacer esto en Unix? Tengo un macbook pro pero soy nuevo en esto. En realidad, son archivos VCF con campos delimitados por tabulaciones. Sí, cada archivo tiene 236 filas que deben omitirse. Me interesa la fila que empieza con #CHROM, que es la fila #237 y la columna #10 de esa fila 237 contiene $i

Respuesta1

Yo usaría 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

Respuesta2

Un script como este puede hacer el trabajo:

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

La "magia" está en la variable FILENAMEque awkcontiene el nombre del archivo de entrada.

Respuesta3

ingrese la descripción de la imagen aquí@YetAnotherUser, vea una imagen del archivo de muestra relacionado con mi solicitud: "Reemplazar el encabezado de una columna determinada con el nombre del archivo"

Respuesta4

Suponiendo que sus archivos estén delimitados por espacios, esto debería 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

Bucle dentro del directorio y tome cada vcfarchivo. Luego elimine la extensión del nombre del archivo ${f_name%.*}y pásela como parámetro a awk.

awkusará esto como nombre de archivo para realizar la sustitución.NOTA: esto debe ejecutarse dentro del mismo directorio del vcfarchivo, si desea ejecutarlo desde otra ruta use lo siguiente:

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

Si los archivos no están delimitados por espacios, solucione awk FS.

EDITAR PARA NUEVAS SOLICITUDES Y MEJORAS BASADAS EN @Ed Morton

Me interesa la fila que empieza con #CHROM, que es la fila #237 y la columna #10 de esa fila 237 contiene $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 nueva versión de los scripts reemplaza el nombre del archivo solo en el campo que desee ($10 = f)y en la línea que desee (NR == 237). El awkparámetro -F\testablece cómo awkver filas y dividirlas en campos.

Nuevamente gracias a @Ed Morton que ha mejorado los scripts originales: Como puede ver, la declaración: mv "$f_name.tmp" "$f_name"que es el comando para sobrescribir el archivo antiguo con el contenido del nuevo (producido por awk) se condensa en una línea: awk '' file > tmp && mv tmp filede esta manera, si el awkEl comando falla, la parte correcta del && no se ejecuta y los datos originales se mantendrán seguros.

información relacionada