BandaAncha

  • 🔍 en 📰 artículos ⏎
  • 🔍 en 💬 foros ⏎
  • 🔍 en 👇 este 💬 foro ⏎
  • 🔍 en 👇 este 💬 tema ⏎
Regístrate Regístrate Identifícate Identifícate

Ejecución en paralelo con bucle infinito en Bash

cisquito
1

He creado el siguiente script en Bash para automatizar la subida de archivos al servidor Lolabits:

1 #!/bin/bash
2 # USO SIN PROXY:
3 # $ curl-loop
4 # USO CON PROXY:
5 # $ curl-loop -x [URL_proxy]
6 mkdir subido
7 while true
8 do
9   for FILE in *.png
10   do
11     curl -F file=@$FILE https://api.lolabits.se/upload -w "\n" $@ | tee -a log.log
12     FILE2=$(basename $FILE .png)
13     FILTER=$(grep $FILE2 log.log)
14     if [ "$FILTER" ] ; then
15       mv $FILE subido
16     fi
17   done 
18 done

El script hace lo siguiente:

  • Detecta los archivos con extensión *.png en el directorio presente y los envía secuencialmente a curl para que los suba al servidor
  • El script puede ejecutarse con o sin dirección proxy
  • Una vez terminada la subida, el resultado se guarda en el archivo de texto "log.log"
  • A continuación lee el archivo "log.log" para comprobar si el PNG usado por curl efectivamente ha sido subido al servidor
  • Si el archivo aparece en "log.log", este es movido al subdirectorio "subido"
  • Como los proxies usados son gratuitos, suelen fallar mucho y curl suele saltarse muchos archivos y los deja sin subir
  • Por si se ha quedado algún PNG sin subir, se utiliza un bucle infinito para que el proceso se repita hasta subir todo

El script funciona bien. Pero lo que intento realizar es conseguir una subida en paralelo también sin errores. Si cambio la línea 11 por esto:

11     echo $FILE | xargs -I1 -P4 -i curl -F file=@{} https://api.lolabits.se/upload -w "\n" $@ | tee -a log.log

Consigo una subida en paralelo de 4 archivos simultáneos. El resultado se guarda en "log.log" pero no me mueve los archivos ya descargados al subdirectorio "subido".

Otro problema, desde luego, es que aunque se hayan subido todos los PNG el bucle se repite infinito y hay que detenerlo manualmente.

Masakr3
2

Como echo un poco de menos trabajar en Linux me he entretenido un rato con esto.

#!/bin/bash
# USO SIN PROXY:
# $ curl-loop
# USO CON PROXY:
# $ curl-loop -x [URL_proxy]

function subida()
{
	FILE=$1
	shift
	OPTS=$@
	curl -s -F "file=@${FILE}" https://api.lolabits.se/upload -w "\n" $OPTS 2>&1 >> log.txt
	resul=$?
	if [ $? -eq 0 ]
	then
		# FUE BIEN MOVEMOS EL FICHERO
		mv $FILE ./subido/.
		return 0
	else
		return 1
	fi

}

if [ ! -d ./subido ]
then
	mkdir subido
fi

for FILE in *.png
do
	(
	until subida $FILE $@
	do
		echo "$FILE - ERROR - REINTENTANDO"
		sleep 0.5
	done
	echo "$FILE - SUBIDO"
	) &

done 
wait

Explicaciones:

  • Nunca se terminaba de ejecutar tu script por el "while true"
  • Ahora se comprueba que no exista el directorio "subido" antes de crearlo
  • Asumo que estás usando el "$@" para meter los argumentos opcionales del "-x [URL_PROXY]"
  • He movido la parte de la subida a una función para facilitar la ejecución en paralelo
  • El "( ) &" dentro del for hace que ejecute todo ese parrafo en paralelo
  • El "until subida $file $@" hace que se ejecute la función de subida hasta que devuelva 0 (true)
  • En vez de buscar en el fichero log el nombre del fichero miro el exit status ($?) del comando curl (que si va bien es 0 peeeeero no he conseguido que me fallara aun subiendo cientos de ficheros varias veces)
  • Si ve que se ha ejecutado bien mueve el fichero al directorio subido y devuelve 0 (true) para que salga del until loop
  • El wait del final es para que se espere el script a que terminen todos los procesos en paralelo
  • En caso de que falle infinitamente seguirá ejecutándose el script indefinidamente
  • El log.txt nunca se limpia tal como está puesto, así que lo tendrás que hacer a mano

Espero que te sirva de ayuda.

🗨️ 1
cisquito

Muchas gracias, amigo, por su ayuda.

Sabe Vd. mucho más de programación Bash que yo, desde luego.

Se me olvidó dos cosas en mi primer mensaje:

  • Lolabits tiene un límite de subida diario de 100 GB
  • El servidor, no sé por qué, en la URL resultante cambia el nombre de la extensión de .png a _png

Dicho lo anterior, cuando el servidor ya no acepta más subidas o el proxy gratuito falla (muy frecuentemente), el método de Vd. arroja el mensaje "$FILE - SUBIDO", envía el archivo al subdirectorio "subido" pero el archivo no se ha subido porque en "log.txt" no aparece su enlace de descarga.

De todas formas, le agradezco mucho su ayuda.

Un saludo.

Masakr3
1

Prueba con este, que procesa el JSON que devuelve el curl para ver si fue bien o mal y por qué.

Te tienes que instalar antes el paquete "jq"

#!/bin/bash
# USO SIN PROXY:
# $ curl-loop
# USO CON PROXY:
# $ curl-loop -x [URL_proxy]

which jq > /dev/null 2>&1
if [ $? -ne 0 ]
then
	echo "ERROR: Es necesario instalar el paquete jq"
	exit 1
fi

function subida()
{
	FILE=$1
	shift
	OPTS=$@
	SALIDA_CURL=$(curl -s -F "file=@${FILE}" https://api.lolabits.se/upload -w "\n" $OPTS 2>&1)
	RESUL=$(echo $SALIDA_CURL | jq '.status')
	URL=$(echo $SALIDA_CURL | jq '.data.file.url.full')
	ERROR=$(echo $SALIDA_CURL | jq '.error.message')
	if [ "$RESUL" = "true" ]
	then
		# FUE BIEN MOVEMOS EL FICHERO
		echo "$(date '+%Y/%b/%d %H:%M:%S') - OK - $FILE - ${URL}" | tee -a log_new.txt
		mv $FILE ./subido/.
		return 0
	else
		echo "$(date '+%Y/%b/%d %H:%M:%S') - FAIL - $FILE - $ERROR"  | tee -a log_new.txt
		return 1
	fi

}

if [ ! -d ./subido ]
then
	mkdir subido
fi

trap "trap - SIGTERM && kill -- -$$" SIGINT SIGTERM EXIT

for FILE in *.png
do
	(
	until subida $FILE $@
	do
		#echo "$FILE - ERROR - REINTENTANDO"
		sleep 0.5
	done
	echo "$FILE - SUBIDO"
	) &

done 
wait

También he arreglado que cuando se cortaba la ejecución del script, con Ctrl+C, no se paraban los procesos en 2º plano (la parte del trap)

El log va ahora a "log_new.txt"

Ejemplo de error:

2023/Feb/03 13:23:41 - FAIL - Cliparts_27.png - "Máximo de archivos por hora excedido."

Si va bien, que ahora siempre me falla la subida, debería salir algo parecido a esto:

2023/Feb/03 13:23:41 - OK - Cliparts_27.png - "[Aquí iria la URL del fichero subido]"

El que ponga la extensión a "_png" en la url no le hagas caso, el enlace en si te vale con la parte de la izq:

lolabits.se/y07fCbV0ya/Cliparts_61_pnglolabits.se/y07fCbV0ya (este es válido también)

Si quieres la url corta cambia esta linea:

URL=$(echo $SALIDA_CURL | jq '.data.file.url.full')

por

URL=$(echo $SALIDA_CURL | jq '.data.file.url.short')

Saludos

🗨️ 1
cisquito

Excelente. Ya casi lo tenemos.

A ver si ahora describo completamente los límites de subida de Lolabits:

  • 20 GB por archivo
  • 500 archivos o 50 GB por hora
  • 5000 archivos o 100 GB por día

Y ahora mi experiencia de uso del script "2.0":

Usándolo con proxy también va bien. Si falla la conexión, lo reintenta hasta que se consigue:

$ ./curl-loop -x socks4://185.154.204.91:4153

curl: (97) connection to proxy closed
2023/feb/03 15:24:13 - FAIL - shot06.png -
curl: (97) connection to proxy closed
2023/feb/03 15:24:14 - FAIL - shot06.png - 
curl: (97) connection to proxy closed
2023/feb/03 15:24:15 - FAIL - shot06.png - 
curl: (97) connection to proxy closed
2023/feb/03 15:24:16 - FAIL - shot06.png - 
2023/feb/03 15:25:18 - OK - shot06.png - "https://lolabits.se/xbjfL5V1y4/shot06_png"

También ha implementado Vd. la subida en paralelo, que era algo que estaba buscando. Muchas gracias.

Aún parece quedar algunos problemas:

  • La subida en paralelo es con todos los archivos PNG presentes en el directorio; de tal manera que si hay 800 archivos realiza una subida en paralelo de 800 a la vez. ¿Es posible ajustar en el script el número máximo de subidas en paralelo (yo suelo usar 4)?
  • El script va configurado para la subida de archivos PNG. ¿Es posible elegir la extensión de los archivos a subir, incluso varias al mismo tiempo, a la hora de llamar al script en la shell? Ejemplo:
$ ./curl-loop .png .jpg .svg ..... -x [URL_del_proxy]

Un saludo.

Masakr3
2

A ver si con la v3:

Cambios:

Ahora se le pueden pasar los siguientes argumentos:

-filetypes png,svg,txt,… (OBLIGATORIO) # no pueden tener espacios entre las extensiones

-parallel 5 (OBLIGATORIO) # Numero entero mayor que 0

-PROXY [DIRECCION DEL PROXY] (OPCIONAL) # el -x para el curl se pone dentro del script

Ejemplo (subir los ficheros txt y mp4 y con 5 subidas en paralelo máximas)

[SCRIPT] -filetypes txt,mp4 -parallel 5

La única limitación que le veo es que si fallan el mismo número de subidas que las del "parallel" se queda indefinidamente reintentando esas, no pasa a los siguientes ficheros hasta que alguna subida haya ido bien.

#!/bin/bash
#
# Argumentos:
# -filetypes [extensiones separadas por comas] ### OBLIGATORIO
# -parallel [num_subidas_paralelo] ### OBLIGATORIO
# -proxy [URL_DEL_PROXY] ### OPCIONAL
#
#
# Ejemplos:
#
# subimos ficheros *.png y *.svg y se suben 3 en paralelo
# [SCRIPT] -filetypes png,svg -parallel 3
#
#
# subimos los ficheros *.txt, 5 en paralelo y usando el proxy google.es
# [SCRIPT] -filetypes txt -parallel 5 -proxy google.es
#
#


which jq > /dev/null 2>&1
if [ $? -ne 0 ]
then
	echo "ERROR: Es necesario instalar el paquete jq"
	exit 1
fi

function subida()
{
	FILE=$1
	SALIDA_CURL=$(curl -s -F "file=@${FILE}" https://api.lolabits.se/upload -w "\n" $PROXY 2>&1)
	RESUL=$(echo $SALIDA_CURL | jq '.status')
	URL=$(echo $SALIDA_CURL | jq '.data.file.url.full')
	ERROR=$(echo $SALIDA_CURL | jq '.error.message')
	if [ "$RESUL" = "true" ]
	then
		# FUE BIEN MOVEMOS EL FICHERO
		echo "$(date '+%Y/%b/%d %H:%M:%S') - OK - $FILE - ${URL}" | tee -a log_new.txt
		mv $FILE ./subido/.
		return 0
	else
		echo "$(date '+%Y/%b/%d %H:%M:%S') - FAIL - $FILE - $ERROR"  | tee -a log_new.txt
		return 1
	fi

}

FILETYPES=""
PARALLEL=""
PROXY=""

while [ $# -gt 0 ]
do
	case $1 in
		-filetypes)
			shift
			FILETYPES=$1
			shift
			;;
		-parallel)
			shift
			PARALLEL=$1
			shift
			;;
		-proxy)
			shift
			PROXY=$1
			shift
			;;
		*)
			echo "ERROR en los argumentos"
			exit 1
			;;
	esac
done

if ! [[ "$PARALLEL" =~ ^[0-9]+$ ]]
then
	echo "ERROR: Valor de -parallel no es un numero entero"
	exit 1
fi

if [ $PARALLEL -eq 0 ]
then
	echo "ERROR: -parallel no puede ser 0"
	exit 1
fi

if [ "$FILETYPES" = "" ]
then
	echo "ERROR: -filetypes no pasado"
	exit 1
fi

FILETYPES=$(echo $FILETYPES | sed 's/,/ *./g' | sed 's/^/*./')

if [ "$PROXY" != "" ]
then
	PROXY="-x $PROXY" 
fi

echo "FILETYPES=$FILETYPES"
echo "PARALLEL=$PARALLEL"
echo "PROXY=$PROXY"

if [ ! -d ./subido ]
then
	mkdir subido
fi



trap "trap - SIGTERM && kill -- -$$" SIGINT SIGTERM EXIT

for FILE in $FILETYPES
do
	while [ $(jobs -p |wc -l) -ge $PARALLEL ]
	do
		# esperamos a que terminen mas trabajos
		sleep 0.5
	done
	(
	until subida $FILE
	do
		#echo "$FILE - ERROR - REINTENTANDO"
		sleep 0.2
	done
	) &


done 
wait
🗨️ 1
cisquito

Amigo, creo que lo hemos conseguido: ya tenemos subida en paralelo a medida, tanto con o sin proxy y con selección de archivos. El único inconveniente es que si la opción -parallel la ajustamos a 1 sola subida, realiza la subida pero el script se queda "en pausa" y no pasa al siguiente archivo. Pero no importa, para eso tengo yo mi propio script.

Lo del bucle infinito con -parallel es problema menor. No utilizo listas de proxies que vayan pasando automáticamente al script, lo hago manualmente hasta que encuentro un proxy medio decente.

Amigo, no sé cómo agradecerle toda su ayuda desinteresada para conmigo. Le deseo todo lo mejor.

Un saludo.