Hola, buenas.
Necesito vuestra ayuda ya que estoy creando un script en bash para convertir los archivos vectoriales de una carpeta a formato .svg usando uniconvertor y me he atrancado a la hora de pasar los nombres de los ficheros a un array y desde allí hacer la conversión.
Paso a mostraros el código que tengo escrito.
#!/bin/bash
# José Antonio Ariza
# El propósito de este script es convertir todos los archivos de un
# directorio usando uniconvertor con una sola orden
# Nos posicionamos en la carpeta Imágenes
cd Imágenes
# Pedimos el nombre de la carpeta que contiene los archivos a convertir
echo "Introduce el nombre de la carpeta a convertir"
read Ruta0
# Definimos la variable $CONTADOR1 a 0 para que comience desde el principio
# del array
CONTADOR1=0
# Definimos el array FICHEROS[] en el que almacenamos los nombres de los
# archivos a tratar
declare -a FICHEROS
# Pedimos el listado de archivos de la carpeta a tratar y lo dirigimos a un
# archivo de texto llamado Ficheros.txt
ls $Ruta0 > Ficheros.txt
# Entubamos la salida de ls hacia el array creado antes
# Esta parte la he copiado de un post encontrado en internet
while read line
echo -e "$line \n"
FICHEROS=$($line)
done < Ficheros.txt
# Definimos la variable CONTADOR2 obteniendo el número total de elementos
# del array
CONTADOR2=${#FICHEROS[@]}
# Incrementamos CONTADOR2 en 1 unidad para que el script trate adecuadamente
# todos los archivos
let CONTADOR3=$CONTADOR2+1
#Cambiamos a la carpeta antes referenciada y creamos dentro una llamada
# Salida
cd $Ruta0
mkdir "Salida"
pwd
# Creamos un bucle while con el que realizamos la conversión de archivos
while [ $CONTADOR1 -lt $CONTADOR3 ]; do
NOMBRE1=$(FICHEROS[$CONTADOR1])
NOMBRE2="Salida/"$(FICHEROS[$CONTADOR1])".svg"
echo $NOMBRE1 $NOMBRE2
uniconvertor $NOMBRE1 $NOMBRE2
let CONTADOR1=CONTADOR1+1
done
El bucle while funciona, ya que hasta ahora estoy usando una versión anterior de la que aquí he puesto que he utilizado para la conversión de aquellas carpetas cuyos ficheros están nombrados con un patrón del tipo XXX0123456.XXX; pasándole esos datos con sendas sentencias echo y read para el número inicial y el final.
Gracias de antemano por vuestra ayuda.

Algunos errores
Primero, el bucle que utilizas para cargar el array FICHEROS es incorrecto, debería ser:
CONTADOR2=0 while read linea do echo $linea FICHEROS[${CONTADOR2}]=$linea CONTADOR2=$((1+$CONTADOR2)) done <<< "`ls $Ruta0`"Luego, para hacer referencia a un elemento del array tienes que utilizar las llaves {} en lugar de parentesis ()
NOMBRE1=${FICHEROS[$CONTADOR1]}Por otra parte CONTADOR3 no lo necesitas y por tanto el bucle del final empezaría en 0 y lo haría mientras fuera menor que CONTADOR2. Además al llamar a uniconvertor deberías encerrar entre "" el nombre de los ficheros por si alguno contiene espacios.
while [ $CONTADOR1 -lt $CONTADOR2 ]; do NOMBRE1=${FICHEROS[$CONTADOR1]} NOMBRE2="Salida/"${FICHEROS[$CONTADOR1]}".svg" echo $NOMBRE1 $NOMBRE2 uniconvertor "$NOMBRE1" "$NOMBRE2" CONTADOR1=$((1+$CONTADOR1)) doneSi no me he equivocado al pegarlo por aquí el script completo te quedaría de la siguiente forma:
#!/bin/bash # José Antonio Ariza # El propósito de este script es convertir todos los archivos de un # directorio usando uniconvertor con una sola orden # Nos posicionamos en la carpeta Imágenes cd Imágenes # Pedimos el nombre de la carpeta que contiene los archivos a convertir echo "Introduce el nombre de la carpeta a convertir" read Ruta0 # Definimos la variable $CONTADOR1 a 0 para que comience desde el principio # del array CONTADOR1=0 # Definimos la variable CONTADOR2 obteniendo el numero total de elementos CONTADOR2=0 while read linea do echo $linea FICHEROS[${CONTADOR2}]=$linea CONTADOR2=$((1+$CONTADOR2)) done <<< "`ls $Ruta0`" #Cambiamos a la carpeta antes referenciada y creamos dentro una llamada # Salida cd $Ruta0 mkdir "Salida" pwd # Creamos un bucle while con el que realizamos la conversión de archivos while [ $CONTADOR1 -lt $CONTADOR2 ]; do NOMBRE1=${FICHEROS[$CONTADOR1]} NOMBRE2="Salida/"${FICHEROS[$CONTADOR1]}".svg" echo $NOMBRE1 $NOMBRE2 uniconvertor "$NOMBRE1" "$NOMBRE2" CONTADOR1=$((1+$CONTADOR1)) doneFdo. Forense asesino, Censor fundamentalista, Fustigador de novatos y Patético maleducado
Arrays en bash
No es nada aconsejable emplear la salida de ls como entrada de otros procesos, sólo para ver por pantalla el contenido del directorio; principalmente porque los nombres de archivos pueden contener espacios y ahí es cuando se lía.
Es mejor usar * cuando sea posible:
FICHEROS=("$Ruta0"/*)Aquí, "$Ruta0"/* se expande a todos los archivos que están en la dirección almacenada en $Ruta0, como si estuviesen entre comillas (es decir, que si hay espacios en un nombre de archivo no pasa nada). Y con los paréntesis se crea el array directamente, y es como si pusieras
FICHEROS=('ruta/foo' 'ruta/bar' 'ruta/pim pam pum')Y luego, el contenido de FICHEROS lo puedes usar directamente en un bucle:
for nombre in "${FICHEROS[@]}" do hacer algo con "$nombre" doneComo colofón, usa comillas alrededor de $ siempre que sea posible (es decir, en vez de $nombre usa "$nombre"), así si hay espacios no se expandirá como varios argumentos separados.
Así que el script quedaría algo como
#!/bin/bash read -p 'Introduce el nombre de la carpeta a convertir: ' Ruta0 # en vez de read, yo la pasaría como argumento, y en vez de $Ruta0 se usaría $1 cd "$Ruta0" Ficheros=(*.*) # con lo de *.* descartamos posibles directorios mkdir -p Salida for nombre in "${Ficheros[@]}" do uniconvertor "$nombre" Salida/"$nombre".svg doneO más fácil todavía:
#!/bin/sh # uso: `./este_script` ó `./este_script directorio` [ -n "$1" ] && cd "$1" # forma corta de hacer un if mkdir -p Salida for nombre in *.* ; do uniconvertor "$nombre" Salida/"$nombre".svg done«E: dpkg was interrupted, you must manually run 'dpkg --configure -a' to correct the problem» significa que dpkg se ha interrumpido y que tienes que ejecutar "sudo dpkg --configure -a" para corregir el problema.
ls como entrada de procesos.
En general puede dar problemas, pero en el ejemplo que le puse no, puedes probar con ficheros que tengan espacios en el nombre y verás que lo trata correctamente uno a uno.
CONTADOR2=0 while read linea do echo $linea FICHEROS[${CONTADOR2}]=$linea CONTADOR2=$((1+$CONTADOR2)) done <<< "`ls $Ruta0`"Fdo. Forense asesino, Censor fundamentalista, Fustigador de novatos y Patético maleducado
¿Y si el nombre de archivo
¿Y si el nombre de archivo contiene saltos de línea?
«E: dpkg was interrupted, you must manually run 'dpkg --configure -a' to correct the problem» significa que dpkg se ha interrumpido y que tienes que ejecutar "sudo dpkg --configure -a" para corregir el problema.
Pues en el hipotético (y para
Pues en el hipotético (y para mí extrañísimo) caso de un fichero con saltos de línea en el nombre, es cierto que no funcionaría; aunque sinceramente, eso me preocupa muy poco porque en los muchos años que llevo perdiendo el tiempo con la informática, no me he encontrado nunca con un fichero que contenga en su nombre un salto de línea, espacios sí pero saltos de línea ni uno.
En cualquier caso me reafirmo en mi respuesta pues lo que estaba en cuestión eran ficheros con espacios en el nombre, y para esos el ls con cuidado funciona perfectamente, al igual que el *, aunque eso sí, este último te da la opción de tratar también ficheros con saltos de línea.
Intentaré recordarlo por si en los próximos 20 años me encuentro con el primer fichero que tenga en su nombre saltos de línea :)
Fdo. Forense asesino, Censor fundamentalista, Fustigador de novatos y Patético maleducado
Bueno, ya, pero...
Era una pregunta un poco trampa... un archivo con enter en el nombre podría existir pero no creo que nadie haya creado nunca un archivo así.
De todas formas, no se recomienda usar ls para obtener listas de archivos; es un programa orientado únicamente a mostrar resultados por pantalla (es decir, a que lo vean humanos, no otros programas). Sobre todo si se puede conseguir lo mismo haciendo for nombre in * o lista=(*)
«E: dpkg was interrupted, you must manually run 'dpkg --configure -a' to correct the problem» significa que dpkg se ha interrumpido y que tienes que ejecutar "sudo dpkg --configure -a" para corregir el problema.
Segunda versión del script
Muchas gracias por vuestra ayuda; he conseguido que me funcione el script, y aún lo he mejorado un poco con un menú que da la opción de elegir a que tipo de archivo conviertes los originales.
El código ha quedado como siguie:
#!/bin/bash # José Antonio Ariza # Urosconv02.sh # El propósito de este script es convertir todos los archivos de un # directorio usando uniconvertor con una sola orden # Pedimos el nombre de la carpeta que contiene los archivos a convertir echo "Introduce el nombre de la carpeta a convertir" read Ruta0 # Pedimos el nombre de la extensión que tendrán los archivos convertidos echo "Selecciona el tipo de archivo de salida" echo "1) AI - Adobe Illustrator 5.0" echo "2) SVG - Scalable Vector Graphics" echo "3) SK - Sketch/Skencil" echo "4) SK1 - Formato sK1" echo "5) CGM - Computer Graphics Metafile" echo "6) WMF - Windows Metafile" echo "7) PDF - Portable Document Format" echo "8) PS - PostEcript" echo "9) PLT - HPGL for cutting plotter files" read Valor1 case $Valor1 in 1) Final1=".ai" ;; 2) Final1=".svg" ;; 3) Final1=".sk" ;; 4) Final1=".sk1" ;; 5) Final1=".cgm" ;; 6) Final1=".wmf" ;; 7) Final1=".pdf" ;; 8) Final1=".ps" ;; 9) Final1=".plt" ;; esac # Definimos la variable $CONTADOR1 a 0 para que comience desde el principio # del array CONTADOR1=0 # Definimos la variable CONTADOR2 obteniendo el numero total de elementos CONTADOR2=0 while read linea do FICHEROS[${CONTADOR2}]=$linea CONTADOR2=$((1+$CONTADOR2)) done <<< "`ls $Ruta0`" echo "Se van a convertir "$CONTADOR2" archivos" echo "Por favor pulse una tecla para continuar" read # Cambiamos a la carpeta antes referenciada y creamos dentro una llamada # como la original cd "$Ruta0" mkdir "$Ruta0" # Creamos un bucle while con el que realizamos la conversión de archivos while [ $CONTADOR1 -lt $CONTADOR2 ]; do NOMBRE1=${FICHEROS[$CONTADOR1]} NOMBRE2="$Ruta0""/"${FICHEROS[$CONTADOR1]}$Final1 echo $CONTADOR1 $NOMBRE1 $NOMBRE2 uniconvertor "$NOMBRE1" "$NOMBRE2" CONTADOR1=$((1+$CONTADOR1)) doneMenos while y más for
Veo que sigues usando contadores raros y usando "`ls $Ruat0`". ¿Por qué no usas directamente
y te quitas de problemas con contadores y arrays y demás? No hacen falta para nada aquí.
Y en cuanto al script, yo lo haría lo menos interactivo posible. Es decir, como va a ser por línea de comandos, le pasas los parámetros que hagan falta al ejecutar el comando. Podrías usar directamente algo como
Así, en vez de $Ruta0 usarías $1 (primer argumento), y en vez de $Final1 usarías .$2
Vamos, yo haría algo así:
#!/bin/sh if [ "$#" -lt 1 -o "$#" -gt 2 ] # si se llama sin argumentos o con más de dos then echo "Uso: $0 tipo [directorio]" exit 0 fi if [ "$#" -eq 2 ] # si se ha especificado directorio, entrar then cd "$2" || exit 1 # si el dir no existe, finalizar fi mkdir -p output for nombre in *.* do uniconvertor "$nombre" "output/$nombre.$1" done«E: dpkg was interrupted, you must manually run 'dpkg --configure -a' to correct the problem» significa que dpkg se ha interrumpido y que tienes que ejecutar "sudo dpkg --configure -a" para corregir el problema.
Estilo de programación
El hecho de usar este estilo de programación se debe, primero a que soy un absoluto novato en la programación de bash (de echo este es mi primer script) y a que cuando aprendí algunos rudimentos de programación en BASIC (hace muchíiiiiisimo) se insistía en que definiésemos y anotásemos todo para seguir la pista de lo que habíamos hecho y que cualquier otro pudiera entender de3 un vistazo lo que intentábamos hacer.
Además, me ayuda a seguir por donde va la ejecución del script; que en el caso del que tú has transcrito, no dudo que funciona a de maravilla, pero no entiendo que y como lo hace.... Aún no llego a ese nivel.
Por otro lado, estoy dándole vueltas a otra versión de este mismo script, a ver si consigo que sea capaz de recorrer todos los subdirectorios que cuelguen de $Ruta0 y convertir los archivos que contengan.
En fin, seguiré pidiendo ayuda por el foro en cuanto me atasque de nuevo...