Script de shell UNIX: como recursivamente mover arquivos para cima de um diretório?

7

Eu tenho um grande número de arquivos pequenos, f, organizados em uma estrutura de diretórios da seguinte forma:

/A/B/C/f

Existem 11 diretórios no nível de A, cada um com cerca de 100 diretórios no nível de B, cada um com cerca de 30 diretórios no nível de C, cada um com um arquivo f.

Como faço para mover todos os arquivos para um nível acima? Por exemplo, dado este conjunto de arquivos ...

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

Eu quero que o diretório /A/B/ contenha 4 arquivos, de f1 a f4. A remoção dos diretórios C não é necessária.

Espero que este seja um problema resolvido, possivelmente envolvendo find , xargs e whatnot . Alguma idéia?

Felicidades,

James

    
por jl6 13.09.2010 / 00:02

4 respostas

8

É bastante simples com o GNU find (encontrado no Linux) ou qualquer outro achado que suporte -execdir :

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

Com um padrão find :

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

Com zsh:

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

Se a estrutura de diretórios sempre tiver o mesmo nível de aninhamento, você não precisará de nenhuma travessia recursiva (mas remover diretórios vazios primeiro):

for x in */*; do; echo mv -i "$x"/*/* "$x"/..; done
    
por 13.09.2010 / 01:00
1

Para esse conjunto de arquivos, isso funcionaria:

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

Mas eu estou esperando que seu problema seja um pouco mais complicado ... Eu não posso responder a isso ... Eu não tenho certeza de como sua estrutura dir é ... Você poderia esclarecer?

    
por 13.09.2010 / 00:13
0

Meu primeiro palpite é

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

contanto que você não especifique -depth , tudo ficará bem. Eu não tentei, então teste primeiro antes de se comprometer com isso.

    
por 13.09.2010 / 00:16
0

Se você quiser mover apenas os arquivos que estão nos diretórios folha (ou seja, você não deseja mover /A/B/file para /A se B contiver subdiretórios), aqui estão algumas maneiras de fazer isso:

Ambos exigem isso

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

Este 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

Isso será mais rápido, mas não gosta de diretórios de fontes vazias:

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