Agregar una columna de valores en un archivo delimitado por tabulaciones

17

¿Cómo puedo agregar una columna de valores en un archivo que tiene un cierto número de filas? Tengo un archivo de entrada como este:

Fichero de entrada:

SPATA17 1   217947738
LYPLAL1 1   219383905
FAM47E  4   77192838
SHROOM3 4   77660162
SHROOM3 4   77660731
SHROOM3 4   77662248

Archivo de salida:

SPATA17 1   217947738 file1
LYPLAL1 1   219383905 file1
FAM47E  4   77192838  file1
SHROOM3 4   77660162  file1
SHROOM3 4   77660731  file1
SHROOM3 4   77662248  file1

En este caso, quiero agregar una columna de valores, hasta el número de filas en el archivo. El valor permanece constante, como "archivo1".

La razón es que tengo 100 de esos archivos. No quiero abrir cada archivo y pegar una columna. También hay alguna forma de automatizar esto, yendo a un directorio y agregando una columna de valores. El valor proviene del nombre del archivo, que debe agregarse en cada fila del archivo en la última / primera columna.

Ron
fuente

Respuestas:

22

Puede usar un bucle de una línea como este:

for f in file1 file2 file3; do sed -i "s/$/\t$f/" $f; done

Para cada archivo de la lista, esto se utilizará sedpara agregar al final de cada línea una pestaña y el nombre del archivo.

Explicación:

  • Usando la -ibandera con sedpara realizar un reemplazo en el lugar, sobrescribiendo el archivo
  • Realizar una sustitución con s/PATTERN/REPLACEMENT/. En este ejemplo, PATTERN es $el final de la línea y REPLACEMENT es \t(= una TAB) y $fes el nombre de archivo de la variable de bucle. El s///comando está entre comillas dobles para que el shell pueda expandir las variables.
janos
fuente
El código funciona. ¿Puede explicar el contenido entre comillas?
Ron
Así como "awk" se usa mientras se trabaja con columnas, 'sed' también se usa para situaciones similares. Soy novato en 'awk' y 'sed'.
Ron
@Ron sedes más práctico para la sustitución de patrones y para guardar en el lugar. Para su requisito de guardar el archivo, era una opción relativamente conveniente. Si no necesita volver a escribir en el mismo archivo que está procesando, awkgeneralmente es mucho más fácil trabajar con él.
janos
Personalmente, los awkseparadores de campo de entrada / salida me hacen tropezar con demasiada frecuencia, por lo que trato de evitar usarlo siempre que sea posible, lo que lo hace sedmás atractivo.
user5359531
11

¡Vamos, por qué ustedes recomiendan esas poderosas herramientas cuando hay un pastecomando!

$ cat a
A
B
C
D
$ cat b
1
2
3
4
$ paste a b
A   1
B   2
C   3
D   4

Con un pequeño truco, puedes usarlo pastepara el propósito del OP. Sin embargo, no reemplazará los archivos en el lugar:

for f in file1 file2 file3; do 
    paste $f <(yes $f | head -n $(cat $f | wc -l)) > $f.new
done

Esto pegará el nombre de archivo respectivo como la última columna de cada archivo en un archivo nuevo filename.new

yegle
fuente
¡Gracias! pasteEs sin duda una joya escondida.
neu242
10

Puedes usar awk:

awk '{print $0, FILENAME}' file1 file2 file3 ...
Cuonglm
fuente
Como cada archivo tiene un nombre diferente, tengo que hacer esto 100 veces. ¿Hay alguna forma de hacerlo una vez?
Ron
No, FILENAMEes una variable awk, se expande al nombre de archivo actual que se awkestá procesando. Simplemente hazlo uno, alimenta todos los archivos awk.
Cuonglm
ok, pero ¿cómo dirigir la salida a un nuevo archivo, de cada archivo? ¿awk almacena cada archivo durante el procesamiento?
Ron
Si tiene GNU awk 4.1.0o posterior, puede usar -ipara editar in situ. De lo contrario, debe redirigir la awksalida a un archivo temporal, luego usar greppara extraer la línea de cada archivo.
Cuonglm
Bueno, puedes hacerlofor file in *; do awk 'BEGIN{OFS="\t"}{print $0, FILENAME}' $file; done
fedorqui