Secuencias de comandos de shell UNIX: ¿cómo mover archivos de forma recursiva hacia arriba en un directorio?

Secuencias de comandos de shell UNIX: ¿cómo mover archivos de forma recursiva hacia arriba en un directorio?

Tengo una gran cantidad de archivos pequeños, f, organizados en una estructura de directorios como esta:

/A/B/C/f

Hay 11 directorios en el nivel A, cada uno con aproximadamente 100 directorios en el nivel B, cada uno con aproximadamente 30 directorios en el nivel C, cada uno con un archivo f.

¿Cómo muevo todos los archivos a un nivel superior? Por ejemplo, dado este conjunto de archivos...

/A/B/C/f1
/A/B/C/f2 /A
/B/C/f3
/A/B/C/f4

Quiero que el directorio /A/B/contenga 4 archivos, del f1 al f4. No es necesario eliminar los directorios C.

Espero que este sea un problema resuelto, que posiblemente involucre a find, xargsy whatnot. ¿Algunas ideas?

Salud,

Jaime

Respuesta1

Es bastante simple con GNU find (como se encuentra en Linux) o cualquier otro find que admita -execdir:

find A -type f -execdir mv -i {} .. \;

Con un estándar find:

find A -type f -exec sh -c 'mv -i "$1" "${1%/*}/.."' sh {} \;

Con zsh:

zmv -Q -o-i 'A/(**/)*/(*)(.)' 'A/$1$2'

Si la estructura de directorios siempre tiene el mismo nivel de anidamiento, no necesita ningún recorrido recursivo (pero primero elimine los directorios vacíos):

for x in */*; do; echo mv -i "$x"/*/* "$x"/..; done

Respuesta2

Para ese conjunto de archivos, esto haría:

$ cd /A/B/C/
$ mv ./* ../

Pero espero que su problema sea algo más complicado... No puedo responder a esto... No estoy muy seguro de cómo es su estructura de directorio... ¿Podría aclararlo?

Respuesta3

Mi primera suposición es

$ find A -type f -exec mv {} .. \;  

Mientras no -depthlo especifiques, debería estar bien. NO lo he probado, así que pruébalo primero antes de comprometerte con él.

Respuesta4

Si solo desea mover archivos que están en directorios hoja (es decir, no desea moverlos /A/B/filesi /Acontienen Bsubdirectorios), aquí hay un par de formas de hacerlo:

Ambos requieren esto

leaf ()
{
    find $1 -depth -type d | sed 'h; :b; $b; N; /^\(.*\)\/.*\n\1$/ { g; bb }; $ {x; b}; P; D'
}
shopt -s nullglob

Éste funciona:

leaf A | while read -r dir
do
    for file in "$dir"/*
    do
        parent=${dir%/*}
        if [[ -e "$parent/${file##*/}" ]]
        then
            echo "not moved: $file"
        else
            mv "$file" "$parent"
        fi
    done
done

Esto será más rápido, pero no le gustan los directorios fuente vacíos:

leaf A | while read -r dir
do
    mv -n "${dir}"/* "${dir%/*}"
    remains=$(echo "$dir"/*)
    [[ -n "$remains" ]] && echo "not moved: $remains"
done

información relacionada