(Solucionado) Asignar valores a array

Imagen de Tholraa
0 puntos

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.

Imagen de joseluis
+1
0
-1

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))
    done

Si 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))
done
+1
0
-1

Fdo. Forense asesino, Censor fundamentalista, Fustigador de novatos y Patético maleducado

Imagen de cousteau
+1
0
-1

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"
done

Como 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
done

O 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
+1
0
-1

«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.
Imagen de joseluis
+1
0
-1

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.

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`"
+1
0
-1

Fdo. Forense asesino, Censor fundamentalista, Fustigador de novatos y Patético maleducado

Imagen de cousteau
+1
0
-1

¿Y si el nombre de archivo contiene saltos de línea?

+1
0
-1

«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.
Imagen de joseluis
+1
0
-1

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 :)

+1
0
-1

Fdo. Forense asesino, Censor fundamentalista, Fustigador de novatos y Patético maleducado

Imagen de cousteau
+1
0
-1

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=(*)

+1
0
-1

«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.
Imagen de Tholraa
+1
0
-1

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))
done
+1
0
-1
Imagen de cousteau
+1
0
-1

Veo que sigues usando contadores raros y usando "`ls $Ruat0`". ¿Por qué no usas directamente

for NOMBRE1 in "$Ruta0"/*

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

tholraa@desktop:~$ ./miscript.sh  directorio/  pdf

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
+1
0
-1

«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.
Imagen de Tholraa
+1
0
-1

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...

+1
0
-1