Anteponga los nombres de las carpetas al nombre del archivo y aplane la estructura del archivo

Tengo un montón de carpetas con varios nombres, por ejemplo

2013-02   Snow and birds
    PICT0001.jpg
    PICT0002.jpg
2013-06   Bicycle trip
    edited_panorama.jpg
    From phone
        DCIM0001.jpg
        DCIM0002.jpg
        DCIM0003.jpg
    From camera
        DSLR
            PICT0001.raw
            PICT0002.raw
        Compact
            S0000001.jpg           

Como puede ver, la estructura general es un nivel variable de subcarpetas anidadas que contienen imágenes. Lo que quiero hacer es aplanar la estructura, agregando el nombre de cada nivel de subcarpetas al nombre del archivo, así:

2013-02   Snow and birds_PICT0001.jpg
2013-02   Snow and birds_PICT0002.jpg
2013-06   Bicycle trip_edited_panorama.jpg
2013-06   Bicycle trip_From phone_DCIM0001.jpg
2013-06   Bicycle trip_From phone_DCIM0002.jpg
2013-06   Bicycle trip_From phone_DCIM0003.jpg
2013-06   Bicycle trip_From camera_DSLR_PICT0001.raw
2013-06   Bicycle trip_From camera_DSLR_PICT0002.raw
2013-06   Bicycle trip_From camera_Compact_S0000001.jpg

¿Cómo se puede lograr esto utilizando un script de Terminal o cualquier otro tipo de script? He encontrado algunas soluciones similares, pero todas parecen depender de un nivel fijo de subcarpetas, mientras que mi estructura de carpetas varía.

Respuestas (3)

Difícil, especialmente si desea mantener todos los espacios, etc. Ejecute lo siguiente en el directorio superior (el que contiene, 2013-02 Snow and birdsetc.):

find . -type f -exec sh -c 'for f do x=${f#./}; echo mv "$x" "${x////_}"; done' {} +

La asignación a xse deshace del principio ./de find, ${x////_}reemplaza todas las apariciones (restantes) de /con _.

Además, he protegido lo real mvcon un correo electrónico echopara que pueda verificar primero si los comandos se ven bien. Vuelva a ejecutar el comando sin echocambiar el nombre/mover los archivos.

¡Funcionó muy bien! Aunque se perdió 3 archivos de 8300 por alguna razón inexplicable. Afortunadamente, expandí todas las carpetas y subcarpetas después de mover los archivos, ¡solo para asegurarme! Los 3 archivos estaban todos anidados a solo 1 nivel de profundidad y en carpetas donde anteriormente había otros archivos con nombres similares (PICT0001.JPG, etc.).
@nohillside ¡Gracias por proporcionar este comando! ¿Hay alguna forma de cambiarlo, para que los archivos no se muevan fuera de sus carpetas originales?
@Philipp La idea general aquí es sacar los archivos de sus carpetas originales. Si tiene otro problema que desea resolver, haga una nueva pregunta.

La respuesta anterior de @nohillside es realmente genial. El único problema con esto es que no tiene en cuenta los archivos con espacios en ellos. Eso hará que algunos de los comandos fallen.

Así que estoy poniendo una respuesta aquí que también lo respaldaría.

Esto solo echomostrará los mvcomandos:

find . -type f -exec sh -c 'for f do x=${f#./}; y="${x// /_}"; echo "mv ${x// /\ } ${y////-}"; done' {} +

Esto solo echomostrará los mvcomandos en su mesa de trabajo directamente:

find . -type f -exec sh -c 'for f do x=${f#./}; y="${x// /_}"; echo "mv ${x// /\ } ${y////-}"; done' {} + | pbcopy

[Cuidado] Esto ejecutará inmediatamente los mvcomandos por usted:

find . -type f -exec sh -c 'for f do x=${f#./}; y="${x// /_}"; eval "mv ${x// /\ } ${y////-}"; done' {} +
Ahora tengo curiosidad :-) ¿Qué escenario específico con espacios hace que mi fragmento de código falle?
Solo si el nombre del archivo incluye espacios. No escapa a los caracteres de espacio en el echomodo con una copia y pegado directos, funciona para la mayoría de los archivos, excepto para aquellos que escupen el error que explica el uso de mvusage: mv [-f | -i | -n] [-v] source target
Bueno, la idea no es copiar/pegar el resultado, sino eliminar el eco una vez que el resultado se vea bien. Pero como siempre, hay muchas maneras :-)
Hay un problema con eval en MacOS cuando el nombre de la imagen contiene paréntesis: Image(30).jpg: eval: line 0: error de sintaxis cerca del token inesperado `('

Para los propósitos de este script, tenía todas sus carpetas contenidas en una carpeta llamada "Filez" en mi escritorio. Este script comienza con un cuadro de diálogo "elegir carpeta" para elegir la carpeta contenedora en la que residen las carpetas "2013-06 Viaje en bicicleta" y "2013-02 Nieve y pájaros". Esto devolverá todos los archivos individuales dentro de todas las carpetas y subcarpetas, cuyos nombres desea cambiar.

set mainFolder to choose folder
set posixPathOfMainFolder to POSIX path of mainFolder
tell application "Finder"
    set theNames to files of entire contents of mainFolder as alias list
end tell
set newFileNames to {}
repeat with aFile in theNames
    set text item delimiters to {posixPathOfMainFolder, "/"}
    set aFile to POSIX path of aFile
    set tempName to text items -1 thru 2 of aFile
    set text item delimiters to "_"
    set end of newFileNames to tempName as text
    set text item delimiters to ""
    tell application "Finder"
        set the name of (aFile as POSIX file as alias) to last item of newFileNames as text
    end tell
end repeat
tell application "Finder"
    set theNames to files of entire contents of mainFolder as alias list
    move theNames to mainFolder
    delete folders of mainFolder
end tell

ingrese la descripción de la imagen aquí