Скрипты оболочки UNIX: как рекурсивно переместить файлы на один каталог вверх?

Скрипты оболочки UNIX: как рекурсивно переместить файлы на один каталог вверх?

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

/A/B/C/f

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

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

/А/Б/С/ф1
/А/Б/С/ф2
/А/Б/С/ф3
/А/Б/С/ф4

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

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

Ваше здоровье,

Джеймс

решение1

Это довольно просто сделать с помощью 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 {} \;

С zsh:

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

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

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

решение2

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

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

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

решение3

Моя первая догадка:

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

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

решение4

Если вы хотите переместить только файлы, находящиеся в конечных каталогах (т. е. вы не хотите перемещать /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

Связанный контент