Estoy tratando de crear un servicio de Automator para el menú contextual del botón derecho del Finder que puede dividir cualquier archivo csv seleccionado, mientras copia el encabezado original en la parte superior de cada archivo.
Mi intento actual es hacer que Automator ejecute este Bash Shell Script :
#!/bin/bash
FILE=$(ls -1 | grep MY_CSV_FILE.csv)
NAME=${FILE%%.csv}
head -1 $FILE > header.csv
tail -n +2 $FILE > data.csv
split -l 50 data.csv
for a in x??
do
cat header.csv $a > $NAME.$a.csv
done
rm header.csv data.csv x??
Este script se dividirá MY_CSV_FILE.csv
en archivos nuevos con un máximo de 50 líneas mientras se copia el encabezado original en la parte superior de cada archivo. Los nuevos archivos tendrán el nombre original anexado con xaa
, xab
, xac
etc.
Con respecto a la configuración de Automator, este es el servicio en el que estoy trabajando actualmente. El problema en este momento es que no puedo pasar el archivo seleccionado en Finder al script Bash.
Darse cuenta de:
#!/bin/bash
de la parte superior del Shell Script y configuré el Shell en: /bin/bash .MY_CSV_FILE.csv
por "$f"
- no estoy seguro si eso es correcto.¿También necesito especificar la ruta usando algo como tanto "$@"
para el archivo de entrada como para los archivos de salida resultantes? No he hecho algo como esto antes, así que no estoy muy familiarizado con esa variable y "$f"
para el caso.
¿Cómo podría hacer que esto funcione? Me gustaría que los archivos resultantes aparezcan en la misma carpeta que el archivo que seleccioné para ejecutar el Servicio, a través del menú contextual del Finder. Sería aún mejor si el Servicio solo aceptara archivos csv.
Escribiría el código un poco diferente, y aquí hay un ejemplo de cómo lo haría:
#!/bin/bash
for f in "$@"; do
if [[ -f $f ]]; then
d="$(dirname "$f")"
n="$(basename "$f")"
t='/tmp'
if [[ ${n##*.} =~ [cC][sS][vV] ]]; then
head -1 "$f" > $t/h.tmp
tail -n +2 "$f" | split -a 3 -l 50 - $t/tmp.
i=1
for s in $t/tmp.a??; do
fn="$d/${n%.*}.$(printf '%03d' $i).csv"
if [[ ! -f $fn ]]; then
cat $t/h.tmp $s > "$fn"
((i++))
else
rm $t/h.tmp $t/tmp.a??
echo "The file '"$fn"' already exists!"
exit
fi
done
rm $t/h.tmp $t/tmp.a??
echo ''
fi
fi
done
/tmp
file.001.csv
, file.002.csv
, etc., en el mismo directorio que los archivos pasados al servicio ./tmp
-a 3
el split
comando a -a 4
y '%03d'
del printf
comando a '%04d'
. También cambiarías $t/tmp.a??
en for s in $t/tmp.a??; do
y rm $t/h.tmp $t/tmp.a??
para:$t/tmp.a???
También agregaría una acción Ejecutar Apple Script al servicio , con el siguiente código :
on run {input, parameters}
if (item 1 of input) is "" then
display notification "Splitting of the target file(s) is finished!" with title "Split CSV File(s)"
else
display notification (item 1 of input as string) with title "Split CSV File(s)"
end if
end run
Esto habilita la salida de los echo
comandos en la acción Ejecutar script de shell para mostrar una notificación si ya existe un archivo de salida o cuando finaliza la división.
Tenga en cuenta que si bien la notificación se puede realizar desde la acción Ejecutar script de Shell usando , no obstante, lo hice de esta manera porque era más fácil de codificar.osascript
Esto se probó en un archivo llamado file.csv en Finder , que tiene 200 líneas, y las imágenes a continuación muestran lo que fue creado por la parte de la acción Run Shell Script del servicio Automator cuando se ejecuta en el archivo .
$a
, es decir x??
, por ejemplo xaa
, xab
etc. Es una preferencia personal para mí, quiero un valor numérico en los nombres de archivo divididos, así que lo codifiqué para eso. . En el código del OP, for a in x??
habría fallado si el archivo fuente tuviera un recuento de líneas superior a 49,950 dividido en 50 archivos de línea porque x??
solo cuenta para 999 archivos donde x???
cuenta para 9999 archivos.split
. hacer los cálculos primero o los cálculos se pueden hacer primero y codificar para adaptarse dinámicamente. Se necesita menos codificación para ajustar el pad y luego verificar primero el conteo de líneas. Si desea garantizar una cantidad muy alta de líneas, incremente los valores aún más que como se indica en mi respuesta para que el pad sea más que adecuado.
-a 3
del split
comando a -a 5
, y '%03d'
del printf
comando a '%04d'
y $t/tmp.a??
en for s in $t/tmp.a??; do
y rm $t/h.tmp $t/tmp.a??
a $t/tmp.a????
, manejará archivos con un recuento de líneas de hasta 4,999,950 archivos divididos en 50 líneas. Para hacerlo aún más fácil, $t/tmp.a??
se puede configurar en $t/tmp.*
y luego solo tendrá que modificar -a 3
el split
comando y '%03d'
el printf
comando configurando cada uno en un número más alto, por ejemplo, -a 8
y '%08d'
manejará archivos con un recuento de líneas de hasta 4,999,999,950 dividido en 50 líneas archivos
Monomeeth
CACEROLA
x??.csv
en mi carpeta de usuario (~
).