Como usar comandos que solo trabajan con un archivo a la vez con todos los ficheros que selecciones

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

En este caso no es necesario seleccionar un fichero de salida puesto que pdftotext genera automáticamente un fichero de texto con el nombre base y la exención .txt si y solo si se trabaja con un solo archivo.

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

Para ingresarle el número se uso el lenguaje interno de awk con la opción “FNR” que enumera cada línea de salida, por lo que el numero se puede poner adelante o detrás del texto.

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

En dependencia de la versión de zenity la opción para el pasword puede ser solo –pasword.

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

Las comillas extras deberán separarse con un espacio donde se use la opción «$0»
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.

Esta opción nos puede resultar muy util si deseamos convertir todo un grupo de videos con mencoder sin que este los una en uno solo; se puede preparar un script para esto y solo tendrían que poner ls --directory %F | sed 's/^/"/' | sed 's/$/"/' | awk '{print "script-convertir-video "$0" "}' | sh && zenity --info --text "Todas las conversiones han terminado"

FIN


15 comentarios, deja el tuyo

Deja tu comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

*

*

  1. Responsable de los datos: Miguel Ángel Gatón
  2. Finalidad de los datos: Controlar el SPAM, gestión de comentarios.
  3. Legitimación: Tu consentimiento
  4. Comunicación de los datos: No se comunicarán los datos a terceros salvo por obligación legal.
  5. Almacenamiento de los datos: Base de datos alojada en Occentus Networks (UE)
  6. Derechos: En cualquier momento puedes limitar, recuperar y borrar tu información.

  1.   Ramiro dijo

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

  2.   croto dijo

    La verdad tahed, tenes gran conocimiento de los comandos de linux. Muy útil!

    1.    KZKG^Gaara dijo

      Sí, sé que aprenderemos mucho con él por acá hahaha.

  3.   hexborg dijo

    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.

    1.    Ankh dijo

      o:
      for i in $(ls -d /camino/a/carpeta/*.ext); do COMANDO “$i”; done;

      1.    hexborg dijo

        Eso tiene buena pinta, pero si los nombres de los ficheros contienen espacios en blanco no funciona. 🙂

        1.    tahed dijo

          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.

          1.    hexborg dijo

            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.

          2.    Hugo dijo

            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.

        2.    Ankh dijo

          Si te fijas las $i está entre comillas. Eso hace innecesario escapar los espacios en blanco.

          1.    hexborg dijo

            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.

  4.   Leo dijo

    Muy bueno, complejo, pero muy interesante.

  5.   helena_ryuu dijo

    esto es alucinante, buenisimo!!!!

  6.   msx dijo

    Excelente, la plasticidad de GNU/Linux no tiene límites.

  7.   Natalia dijo

    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