8

У меня есть большое количество маленьких файлов, расположенных в структуре каталогов следующим образом:

/A/B/C/f

Существует 11 каталогов на уровне A, каждый из которых содержит около 100 каталогов на уровне B, каждый из которых содержит около 30 каталогов на уровне C, каждый из которых содержит один файл f.

Как мне переместить все файлы на один уровень вверх? Например, учитывая этот набор файлов ...

/ А / В / С / f1
/ А / В / С / f2
/ А / В / С / f3
/ А / В / С / f4

Я хочу, чтобы каталог /A/B/ содержал 4 файла, от f1 до f4. Удаление каталогов C не является необходимым.

Я надеюсь, что это решенная проблема, возможно, включающая find , xargs и whatnot . Есть идеи?

Ура,

Джеймс

4 ответа4

9

Это довольно просто с GNU find (как найдено в Linux) или любым другим find, который поддерживает -execdir:

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

Со стандартной find:

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

С зш:

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

Если структура каталогов всегда имеет одинаковый уровень вложенности, рекурсивный обход не требуется (но сначала удалите пустые каталоги):

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

Для этого набора файлов это будет сделано:

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

Но я ожидаю, что ваша проблема несколько сложнее ... Я не могу ответить на это ... Я не совсем уверен, как твоя структура dir ... Не могли бы вы уточнить?

0

Мое первое предположение

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

до тех пор, пока вы не укажете -depth все должно быть в порядке. Я НЕ пробовал, поэтому сначала проверьте его, прежде чем совершить это.

0

Если вы хотите переместить только файлы, находящиеся в конечных каталогах (то есть вы не хотите перемещать /A/B/file в /A если B содержит подкаталоги), вот несколько способов сделать это:

Оба требуют этого

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

Этот работает:

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

Это будет быстрее, но оно не любит пустые исходные каталоги:

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

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .