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

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

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

/A/B/C/f

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

Como movo 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

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, xargse whatnot. Alguma ideia?

Saúde,

James

Responder1

É bastante simples com GNU find (como encontrado no Linux) ou qualquer outro find 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 primeiro remova os diretórios vazios):

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

Responder2

Para esse conjunto de arquivos, isso faria:

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

Mas espero que o seu problema seja um pouco mais complicado... Não posso responder... Não tenho muita certeza de como está a sua estrutura de diretórios... Poderia esclarecer?

Responder3

Meu primeiro palpite é

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

contanto que você não especifique, -depthtudo bem. Eu NÃO tentei, então teste primeiro antes de se comprometer.

Responder4

Se você deseja mover apenas arquivos que estão em diretórios folha (ou seja, não deseja mover /A/B/filepara /Aif Bcontém 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\1$/ { 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 origem vazios:

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

informação relacionada