1

По сути, у меня есть набор каталогов, которые постоянно заполняются .rar, и мне нужно иметь возможность извлекать их на месте с автоматическим удалением оставшихся.(Rar | rXX) файлов. Как бы я пошел по этому поводу?

Примечание: я не могу удалить их все после того, как это сделано, их нужно удалить, так как скрипт завершает один набор rar.

Пример структуры каталогов:

/
/folder1/
        /file1.rar
        /file1.r00
        /file1.r01
/folder2/
        /sub.folder1/
                    /file2.part001.rar (contains a directory "file2")
                    /file2.part002.rar
                    /file2.part003.rar
        /sub.folder2/
                    /file3.rar
                    /file3.r00
                    /file3.r01

Ожидаемый результат:

/
/folder1/
        /file1.ext
/folder2/
        /sub.folder1/
                    /file2/
                          /file2.ext
        /sub.folder2/
                    /file3.ext

2 ответа2

3

Вариант для Bash:

#!/bin/bash
if [ ! -d "${1}" ]; then
    printf '%s: error: mandatory argument is not a valid directory.' "${0##*/}" 1>&2
    exit 1
fi

shopt -s extglob
for i in "${1}"/**/*.rar; do
    cd -- "${i%/*}"
    file=${i##*/}
    unrar e -- "${file}" && rm -- @(${file}|${file%.rar}.r[[:digit:]][[:digit:]])
    cd - >/dev/null
done

Архивы RAR также могут быть "юридически" названы, например, myarchive.part001.rar и т.д., И это будет необходимо обрабатывать отдельно каким-то образом, если такие архивы существуют. Прагматичный способ решения этой проблемы - заменить

unrar e -- "${file}" && rm -- @(${file}|${file%.rar}.r[[:digit:]][[:digit:]])

с

unrar e -o- -- "${file}"
if [ $? -eq 0 -o $? -eq 10 ]; then
    rm -- @(${file}|${file%.rar}.r[[:digit:]][[:digit:]])
fi

но будьте осторожны с этим, это очистит файлы RAR, даже если указан код ошибки 10 ("Нет файлов для извлечения"), и, таким образом, обычно не рекомендуется в неизмененном виде.


В целом, может быть лучше просто сохранить материал в заархивированном виде и вместо этого использовать распаковку «на лету» или что-то подобное, когда вы захотите ее использовать. Сохранение архивного формата может иметь и другие преимущества.

1

Я пишу это с головы до головы, так что это непроверенный код, но он должен вывести вас на правильный путь. Он в основном идет по дереву, на которое вы указываете, в поисках файлов .rar. Найдя его, он распакует его на месте и удалит исходный архив, если unrar не вернет ненулевое значение. При попадании в папку, функция просто вызывает себя, вызывая ее рекурсивность.

#!/bin/bash

[[ ! -d "$1" ]] && echo "Please point me at a directory!" && exit 1

function recursively_extract_all_rars_in() {
    local x=`pwd` f
    cd "$1"


    for f in (*); do
        [[ -d "$f" ]] && recursively_extract_all_rars_in "$f"
        [[ -f "$f" ]] && [[ "$f" =~ "*.rar" ]] && unrar e "$f" && rm ${f%%.*}.r??
    done
    cd "$x"
}

recursively_extract_all_rars_in "$1"

Имя функции полностью произвольно. Мне нравится, когда они читают как настоящий английский, когда приводятся их аргументы. [[ -d /path ]] возвращает true, если путь существует и является каталогом. -f делает соответствующие файлы. [[ "string" =~ "pattern"]] - это bashism, который позволяет сопоставлять шаблоны в строках. Это работает в основном так же, как шаблоны глобуса.

Строка local x=pwd f может быть загадочной, но она просто определяет две локальные переменные: одну с именем x, для хранения pwd , и одну с именем f, неинициализированную (она инициализируется в цикле for ниже, я просто объявляю ее здесь, так что местный).

Хранение pwd и возврат к нему, если ваша функция использует cd - это хорошо (tm).

Обратите внимание, что использование вывода ls программно - это, как правило, Bad Mojo, и вам следует избегать его, как вредителя, в пользу find . Если какое-либо из ваших имен файлов содержит пробел, использование ls в вашем скрипте приведет к большим ошибкам. Вы были предупреждены.

ЗШ

Я не уверен, что вы можете сделать то же самое в Bash, но в ZSH я бы поместил следующее где-то в .zshrc

function recursive_unrar() {
    for f in **/*.rar; do
        local cwd=`pwd` fbn=${f##*/}
        cd "${f%/*}"
        unrar e "$fbn"
        rm "${fbn%%.*}.r{01..99} $fbn"
        cd "$cwd"
    done
}

А затем просто позвоните изнутри соответствующей папки.

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