Muchas veces necesitamos ejecutar una secuencia de comandos ya sea para convertir un pdf en texto, convertir los ficheros .doc en html, etc; la cuestión es que dichos comandos solo aceptan un fichero a la vez y eso nos resulta muy tedioso si necesitamos realizar la misma tarea a varios archivos sobre todo cuanto realizamos un script.
Yo les propongo una solución para este problema usando ls, sed, grep, awk y sh. Lo que haremos será crear la linea de comandos correcta en cada fila y ejecutarlas con sh, y como sh ejecutara una linea a la vez no se aumentara el consumo de memoria ram que con otros métodos pueden hasta congelar a las maquinas de poca potencia.
Veamos como realizar realizar dicha secuencia de comando.
1- Lo primero que tenemos que hacer sera introducir los ficheros que se usaran mediante ls:
ls --directory /camino/a/carpeta/*.ext
2- Luego necesitaremos que dichos ficheros pasen encomillados «/camino/a grupo de
ficheros«
ls --directory /camino/a/carpeta/*.ext | sed 's/^/"/' | sed 's/$/"/'
3- Ahora awk estará listo para recibir los datos.
ls --directory /camino/a/carpeta/*.ext | sed 's/^/"/' | sed 's/$/"/' | awk '{print $0}'
Debido a que awk tiene su propio lenguaje necesitaremos separar las comillas que queramos que salgan para encomillar un texto entre otras funciones necesitaremos usar la barra invertida \ veamos como separar algunas.
Separar una comilla
\”
Mostrar una barra invertida en la salida (necesitaremos teclear tres barras)
\\\
Algunas veces necesitaremos un separador aislador, solo saldrá en la salida el texto o las comillas que aparezcan dentro de las dos barras invertidas.:
'""'\"\'""'
4- Veamos como renombrar todos los ficheros que se listen usando el comando mv solamente para introducir un sufijo. (ahora para listar el fichero necesitaremos usará la combinación «$0» siempre que necesitemos usarla)
ls --directory /camino/a/carpeta/*.ext | sed 's/^/"/' | sed 's/$/"/' | awk '{print "mv "$0" \"`dirname
«$0″`/Texto-cualquiera-`basename «$0″`\» «}’ | sh
Nota se le agrega al final como se muestra en la anterior secuencia la combinación « | sh » que redirige la tubería a este interprete de ordenes
Veamos algunos ejemplos preparados para crear un script.
Ejemplos:
1- Convertir todos los pdf que se listen en ficheros de texto.
ls --directory “$@” | sed 's/^/"/' | sed 's/$/"/' | awk '{print "pdftotext",$0}' | sh
2- Digamos que queremos aplicarle un efecto a una imagen pero sin modificar la original, veamos un ejemplo con el efecto wave muy conocido por el logotipo de Windows XP, pues se trata de una bandera con efectos oondulados (para apreciar mejor este efecto se recomienda usar como imagen resultante la extensión .png).
ls --directory “$@” | sed 's/^/"/' | sed 's/$/"/' | awk '{print FS="convert -wave 25x150
"$0"","\"\`dirname "$0"`/`basename "$0" | sed '"'"s/\\\\.[[:alnum:]]*$//"'"'`-wave.`basename "$0" |
rev | awk -F . \'"'"'\{print $1}\'"'"'\ | rev`'""'\"\'""' "}' | sh
Nota: en esta secuencia se realizan varias pasadas:
- Una para obtener la carpeta donde se encuentra el fichero con dirname
- Otra para obtener el nombre base, pero eliminando la extensión de dicho fichero
- Otra para obtener la exención de dicho fichero.
3- Veamos ahora como renombrar un grupo de ficheros poniéndole el número correspondiente delante del nombre (sufijo numérico).
ls --directory “$@” | sed 's/^/"/' | sed 's/$/"/' | awk '{print FS="mv "$0" '""'\"\'""'`dirname
"$0"`/"FNR"-`basename "$0"`'""'\"\'""' "}' | sh
Veamos como poner un prefijo númerico (poner un número al final, pero antes de la exención) esta opción solo es valida si el archivo tiene una extensión.
ls --directory “$@” | sed 's/^/"/' | sed 's/$/"/' | awk '{print FS="mv "$0" \"`dirname
"$0"`/`basename "$0" | sed '\'s/\\\\.[[:alnum:]]*$//\''`-"FNR".`echo "$0" | rev | awk -F .
'""'\'\'""'{print $1}'""'\'\'""' | rev `\" " }' | sh
4- Veamos un ejemplo donde tendremos que introducir datos o seleccionar un grupo de funciones tomando como ejemplo el caso donde le quitamos la protección por contraseña a varios ficheros de pdf que tienen la misma clave. (En este caso usaremos zenity como caja de dialogo)
zenity --entry --hide-text --text "introduzca la clave de desbloqueo" > $HOME/.cat && ls
--directory “$@” | sed 's/^/"/' | sed 's/$/"/' | awk '{print FS="pdftk "$0" input_pw `cat
$HOME/.cat` output \"`dirname "$0"`/`basename "$0" .pdf`-unlock.pdf\" "}' | sh && rm
$HOME/.cat
Como vieron el objetivo es hacer un cat de un fichero que se creara al principio de la linea una sola vez y luego sera eliminado una vez concluya la conversión.
5- Otra utilidad es, cuando necesitamos descomprimir varios ficheros compactado en .zip
ls --directory “$@” | sed 's/^/"/' | sed 's/$/"/' | awk '{print "unzip -x "$0" "}' | sh
Ejemplo
"unzip -x "$0" "
6- Veamos un ejemplo para proteger un pdf con contraseña permitiendo la lectura pero protegido contra la copia impresión u otras opciones, (las opciones que se listen en la caja de dialogo serán las que se permitirán en el pdf, si no quiere permitir ninguna de ellas no seleccione ninguna).
zenity --separator " " --multiple --text "Seleccione los Opciones que quiere permitir" --column "Opciones" --list "Printing" "DegradedPrinting" "ModifyContents" "CopyContents" "ScreenReaders" "ModifyAnnotations" "AllFeatures" > $HOME/.cat && zenity --entry --hidetext --text "Teclee la contraseña de protección" > $HOME/.cat2 && ls --directory "$@" | sed 's/^/"/' | sed 's/$/"/' | awk '{print FS="echo \"pdftk \\\"`echo "$0"`\\\" output \\\"`dirname "$0"`/`basename "$0" .pdf`-locked.pdf\\\" allow `cat $HOME/.cat` owner_pw \"`cat $HOME/.cat2`\"\" | sh "}' | sh && rm $HOME/.cat $HOME/.cat2
Con estos ejemplos queda bastante ejemplificado como usar esta opción para convertir, modificar o renombrar varios archivos con una sola secuencia de comandos y no convirtiéndolos a mano uno por uno. El consumo de memoria con esta opción es mínimo, en dependencia del comando que se este usando, ya que no los convierte al mismo tiempo sino uno detrás del otro.
ls --directory %F | sed 's/^/"/' | sed 's/$/"/' | awk '{print "script-convertir-video "$0" "}' | sh && zenity --info --text "Todas las conversiones han terminado"
FIN
¿No sería mucho, pero MUCHÍSIMO más facil hacer todo esto usando expresiones regulares o comodines? No entiendo cuál es la diferencia entre eso y complicarse tanto la vida con esto.
La verdad tahed, tenes gran conocimiento de los comandos de linux. Muy útil!
Sí, sé que aprenderemos mucho con él por acá hahaha.
Creo que esto es mucho más facil:
ls -d /camino/a/carpeta/*.ext | while read file; do COMANDO «$file»; done
En lugar de COMANDO puedes poner lo que quieras y funciona aunque los ficheros contengan espacios en blanco siempre que pongas $file entre comillas. No es necesario usar sed para eso ni generar los comandos con awk. Además esto lanza menos procesos.
o:
for i in $(ls -d /camino/a/carpeta/*.ext); do COMANDO “$i”; done;
Eso tiene buena pinta, pero si los nombres de los ficheros contienen espacios en blanco no funciona. 🙂
De hecho hexborg por eso es que se encomilla el texto de salida al inicio y al final por cada linea con esta opción:
ls –directory | sed ‘s/^/»/’ | sed ‘s/$/»/’
Aclaro que se puede usar find para que busque en los subdirectorios.
Pero con mi truco no hace falta. ls saca los nombres completos de los ficheros uno en cada linea y read lee linea a linea y deja el nombre del fichero en la variable file tanto si tiene espacios en blanco o no. Sólo hace falta poner comillas alrededor de $file al usarlo en el comando.
Estoy de acuerdo que en find puede ser menos engorroso. Tomemos este ejemplo del artículo:
ls --directory “$@” | sed 's/^/"/' | sed 's/$/"/' | awk '{print "pdftotext",$0}' | sh
Bien podría conseguirse lo mismo así, y probablemente se ejecute más rápido:
find . -type f -print0 | xargs -0 pdftotext
Dicho esto, el artículo es bienvenido, siempre es bueno conocer maneras alternativas de hacer algo.
Si te fijas las $i está entre comillas. Eso hace innecesario escapar los espacios en blanco.
Si, pero el operador $() expande los nombres de fichero sin poner comillas en ningún sitio, así que la variable i ya pilla los nombres de los ficheros cortados. Pruébalo en una terminal en un directorio que tenga ficheros con espacios en los nombres.
Muy bueno, complejo, pero muy interesante.
esto es alucinante, buenisimo!!!!
Excelente, la plasticidad de GNU/Linux no tiene límites.
Estimado blogger,
Soy Natalia, Responsable de Comunicación de Paperblog. Tras haberlo descubierto, me pongo en contacto contigo para invitarte a conocer el proyecto Paperblog, http://es.paperblog.com, un nuevo servicio de periodismo ciudadano. Paperblog es una plataforma digital que, a modo de revista de blogs, da a conocer los mejores artículos de los blogs inscritos.
Si el concepto te interesa sólo tienes que proponer tu blog para participar. Los artículos estarían acompañados de tu nombre/seudónimo y ficha de perfil, además de varios vínculos hacia el blog original, al principio y al final de cada uno. Los más interesantes podrán ser seleccionados por el equipo para aparecer en Portada y tú podrás ser seleccionado como Autor del día.
Espero que te motive el proyecto que iniciamos con tanta ilusión en enero de 2010. Échale un ojo y no dudes en escribirme para conocer más detalles.
Recibe un cordial y afectuoso saludo,
Natalia