Cómo concatenar un número variable de csv, eliminando sus filas de encabezado?

Tengo un directory con varios cientos de files csv cuyos nombres de file comienzan con dos dígitos {01..84} . Varios cientos >> 84, así que, obviamente, algunos nombres de file comienzan con el mismo prefijo. Deseo concatenar los files cuyos nombres de file comienzan con el mismo prefijo. Esto es lo que tengo:

 #!/bin/bash for i in {01..84}; do #declare array to store files with same prefix declare -a files=() echo "Processing $i" for j in `ls $i*.csv`; do #add files with same prefix to array files=("${files[@]}" "$j") done #cat first file including header with the rest of the files without the headers cat < ${files[@]:0:1} <(tail -n+2 ${files[@]:1}) > "$i".csv done 

Hasta ahora todo bien … solo, se detiene a $i = 22 a la mitad (error repetible) y contamina los files de salida con líneas en blanco y encabezados como "==> 19XXX.csv <==" (sin citas).

  1. ¿Qué debería cambiar en el código para get solo un buen file csv limpio para cada prefijo sin que el script se cuelgue?

  2. ¿Hay alguna utilidad de bash precomstackda a la que pueda llamar para hacer esto de una manera más rápida y sencilla?

 #!/bin/bash for i in {01..84}; do x=$(printf '%02d' $i) set -- $x?*.csv if [ -f "$1" ]; then cp "$1" $i.csv shift if [ -f "$1" ]; then tail -q -n +2 "$@" >> $x.csv fi fi done 

Para cada prefijo, establece la list de files con ese prefijo como arguments para que pueda usar $1 para acceder al primero, etc.

Si $1 es un file (para captar el caso donde no hay files con el prefijo dado) entonces copie ese file a prefix.csv. Luego verifique si había más de un file con ese prefijo al cambiar el primer file y verificando que el siguiente también es un file. Si es así, omita la línea del encabezado de cada file mediante el command tail y añádalo al prefix.csv.

La opción -q a la tail consiste en suprimir la tail línea del encabezado que se agregará si se pasa más de un file en la list de arguments; aquí es de donde ==> 19XXX.csv <== sus ==> 19XXX.csv <== líneas.

Probablemente solo se necesita la opción -q en su solución, pero me parece demasiado complicado, ya que requiere bash para almacenar en búfer la salida del command tail etc., que puede ser la causa de que la secuencia de commands se detenga (¿se cuelgue?) Prematuramente.

EDITAR: añadido x=$(printf '%02d' $i) como {01..84} expande a 1 2 3 … sin ceros a la izquierda.

 #!/bin/sh for i in {01..84} do cat $i*.csv > $i.csv-concat rm $i*.csv mv $i.csv-concat $i.csv done 

no se olvide de cat, es una herramienta de concatenación, tail también puede hacer el trabajo y eliminar el encabezado.

 #!/bin/sh pushd [workdir] for i in {01..84} do echo $i*.csv | xargs -n 1 tail -n+2 > $i.csv-concat rm $i*.csv mv $i.csv-concat $i.csv done popd 

Solución de código de trabajo para cualquiera que acaba de venir aquí para copyr y pegar basado en wurtel's:

 #!/bin/bash for i in {01..84}; do #declare array to store files with same prefix declare -a files=() echo "Processing $i" for j in `ls $i*.csv`; do #add files with same prefix to array files=("${files[@]}" "$j") done #cat first file including header with the rest of the files without the headers if [ ${#files[@]} -gt 1 ]; then cat <(cat ${files[@]:0:1}) <(tail -q -n+2 ${files[@]:1}) > "$i".csv else cat <(cat ${files[@]:0:1}) > "$i".csv fi done 

La forma en que Stéphane Chazelas usa awk. Mucho más limpio.

 #!/bin/bash for i in {01..84}; do echo "processing $i" awk 'NR==FNR||FNR>1' $i?*.csv >> "$i".csv done