Si bien he estado usando BASH durante varios años, mi experiencia con las secuencias de comandos BASH es relativamente limitada.
Mi código es el siguiente. Debe tomar toda la estructura de directorios desde el directorio actual y replicarla en $OUTDIR
.
for DIR in `find . -type d -printf "\"%P\"\040"`
do
echo mkdir -p \"${OUTPATH}${DIR}\" # Using echo for debug; working script will simply execute mkdir
echo Created $DIR
done
El problema es que aquí hay una muestra de la estructura de mi archivo:
$ ls
Expect The Impossible-Stellar Kart
Five Iron Frenzy - Cheeses...
Five Score and Seven Years Ago-Relient K
Hello-After Edmund
I Will Go-Starfield
Learning to Breathe-Switchfoot
MMHMM-Relient K
Tenga en cuenta los espacios: -S Y for
toma los parámetros palabra por palabra, por lo que la salida de mi script se ve así:
Creating directory structure...
mkdir -p "/myfiles/multimedia/samjmusicmp3test/Learning"
Created Learning
mkdir -p "/myfiles/multimedia/samjmusicmp3test/to"
Created to
mkdir -p "/myfiles/multimedia/samjmusicmp3test/Breathe-Switchfoot"
Created Breathe-Switchfoot
Pero lo necesito para tomar nombres de archivos completos (una línea a la vez) de la salida de find
. También he intentado hacer find
poner comillas dobles alrededor de cada nombre de archivo. Pero esto no ayuda.
for DIR in `find . -type d -printf "\"%P\"\040"`
Y salida con esta línea cambiada:
Creating directory structure...
mkdir -p "/myfiles/multimedia/samjmusicmp3test/"""
Created ""
mkdir -p "/myfiles/multimedia/samjmusicmp3test/"Learning"
Created "Learning
mkdir -p "/myfiles/multimedia/samjmusicmp3test/to"
Created to
mkdir -p "/myfiles/multimedia/samjmusicmp3test/Breathe-Switchfoot""
Created Breathe-Switchfoot"
Ahora, necesito alguna forma en la que pueda iterar de esta manera, porque también deseo ejecutar un comando más complicado que involucre gstreamer
a cada archivo en una estructura similar. ¿Cómo debería estar haciendo esto?
Editar: Necesito una estructura de código que me permita ejecutar múltiples líneas de código para cada directorio / archivo / bucle. Lo siento si no estaba claro.
Solución: inicialmente intenté:
find . -type d | while read DIR
do
mkdir -p "${OUTPATH}${DIR}"
echo Created $DIR
done
Esto funcionó bien en su mayor parte. Sin embargo, más tarde descubrí que, dado que la tubería da como resultado que el bucle while se ejecute en una subshell, las variables establecidas en el bucle no estuvieron disponibles más tarde, lo que dificultó la implementación de un contador de errores. Mi solución final (de esta respuesta en SO ):
while read DIR
do
mkdir -p "${OUTPATH}${DIR}"
echo Created $DIR
done < <(find . -type d)
Esto más tarde me permitió incrementar condicionalmente las variables dentro del ciclo que permanecerían disponibles más adelante en el script.
/
caracteres no imprimibles. Pero todo está permitido excepto/
y,\0
por lo tanto, debe permitirlos.Respuestas:
Necesitas canalizarlo
find
en unwhile
bucle.Además, no necesitará usar
-printf
en este caso.Puede hacer esta prueba contra archivos con nuevas líneas en sus nombres, si lo desea, utilizando un delimitador de nullbyte (que es el único carácter que no puede aparecer en una ruta de archivo * nix):
También encontrarás que usar en
$()
lugar de backticks es más versátil y fácil. Se pueden anidar mucho más fácilmente y las citas se pueden hacer mucho más fácilmente. Este ejemplo artificial ilustrará estos puntos:Intenta hacer eso con backticks.
fuente
"$dir"
, es preferible usarlo"${dir}"
: es fácil distinguir entre $ {dir} name y $ {dirname}, pero $ dirname podría interpretarse de cualquier manera.read
lee una línea completa${dir}
, por lo que el IFS no importa.find … -print0 | xargs -0 …
porque el delimitador que usa corresponde exactamente al único carácter que no está permitido en los nombres de nombres POSIX: NUL (U + 0000).while
. @Chris Johnsen: Cierto, pero incluso los programas de extracción de música no tienden a incluir avances de línea en sus nombres de archivo. Y si lo hacen, quiero saber (es decir: algo va mal) y deshacerse de ellos de inmediato ...Vea esta respuesta que escribí hace unos días para obtener un ejemplo de un script que maneja nombres de archivos con espacios.
Sin embargo, hay una forma un poco más complicada (pero más concisa) de lograr lo que estás tratando de hacer:
-print0
le dice a find que separe los argumentos con un valor nulo; el -0 a xargs le dice que espere argumentos separados por nulos. Esto significa que maneja bien los espacios.-I {}
le dice a xargs que reemplace la cadena{}
con el nombre del archivo. Esto también implica que solo se debe usar un nombre de archivo por línea de comando (xargs normalmente rellenará tantos como quepan en la línea)El resto debería ser obvio.
fuente
El problema que está encontrando es que la declaración for responde al hallazgo como argumentos separados. El delimitador del espacio. Debe usar la variable IFS de bash para no dividirse en el espacio.
Aquí hay un enlace que explica cómo hacer esto.
Establezca su búsqueda para generar su delimitador de campo después del% P y establezca su IFS adecuadamente. Elegí punto y coma, ya que es muy poco probable que se encuentre en sus nombres de archivo.
La otra alternativa es llamar a mkdir desde find directamente a través de
-exec
si puede omitir el bucle for por completo. Eso si no necesita hacer ningún análisis adicional.fuente
/
POSIX y:
sistemas de archivos DOS. Hay caracteres ilegales para diferentes sistemas de archivos que puede elegir para el IFS. Algo más complicado y es mejor usar Perl.find
devuelve nombres de archivo con rutas que incluyen una barra inclinada. Intente cambiar el punto y coma en su secuencia de comandos a una barra diagonal y el eco imprimirá el directorio y el nombre del archivo en líneas separadas.while
opción, pero esto también parece bastante viable. Sí, en mi estructura similar más tarde necesitaba analizar más. (El nombre de archivo de entrada sería .ogg, que se pasaría comofilesrc
en la tubería gst, pero se generaría un equivalente que termina en .mp3 basado en el directorio de salida y también se pasa a la tubería comofilesink
, y esto, por supuesto, debe hacerse para cada archivo, junto con algunosecho
para el usuario.)Si el cuerpo de su ciclo es más que un solo comando, es posible usar xargs para manejar un script de shell:
Asegúrese de incluir el guión final (o alguna otra 'palabra') si el shell es de la variedad Bourne / POSIX (se usa para establecer $ 0 en el script del shell). Además, se debe tener cuidado con las citas, ya que el script de shell se está escribiendo dentro de una cadena entre comillas en lugar de directamente en el indicador.
fuente
en su pregunta actualizada que tiene
esto debería ser
fuente
fuente
o para hacer todo mucho menos complicado:
esto replica la estructura de directorios de SRC en DST.
fuente
while
...do
...done
más tarde para hacer un procesamiento similar desde find, lo que requeriría que se ejecutaran varias líneas de código en cada archivo (modificar cadena, echo, gst-launch, etc. ) yrsync
no lograría esto. Es por eso que especifiqué que necesitaba poder ejecutar un conjunto de comandos más complicado dentro de una estructura similar. Mi secuencia de comandos utiliza esta estructura de bucle dos veces, por lo que para la pregunta publiqué la que tiene menos grosería en el medio.Si tiene instalado GNU Parallel http: // www.gnu.org/software/parallel/, puede hacer esto:
Mire el video de introducción de GNU Parallel para obtener más información: http://www.youtube.com/watch?v=OpaiGYxkSuQ
fuente