Как рекурсивно распаковать архивы в каталоге и его подкаталогах из командной строки Unix?

на unzip команда не имеет возможности рекурсивно распаковывать архивы.

Если у меня есть следующая структура каталогов и архивов:

/Mother/Loving.zip
/Scurvy/Sea Dogs.zip
/Scurvy/Cures/Limes.zip

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

/Mother/Loving/1.txt
/Mother/Loving.zip
/Scurvy/Sea Dogs/2.txt
/Scurvy/Sea Dogs.zip
/Scurvy/Cures/Limes/3.txt
/Scurvy/Cures/Limes.zip

какую команду или команды я бы выдал?

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

9 ответов


Если вы хотите извлечь файлы в соответствующую папку, вы можете попробовать это

find . -name "*.zip" | while read filename; do unzip -o -d "`dirname "$filename"`" "$filename"; done;

мульти-обрабатываемая версия для систем которые могут отрегулировать высокий и / о:

find . -name "*.zip" | xargs -P 5 -I fileName sh -c 'unzip -o -d "$(dirname "fileName")/$(basename -s .zip "fileName")" "fileName"'

вот одно решение, которое включает в себя команды find и цикл while:

find . -name "*.zip" | while read filename; do unzip -o -d "`basename -s .zip "$filename"`" "$filename"; done;

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

find . -name '*.zip' -exec sh -c 'unzip -o -d "${0%.*}" ""' '{}' ';'

обратите внимание, что вы можете легко обрабатывать больше типов файлов (например,.jar), добавляя их с помощью -o, например:

find . '(' -name '*.zip' -o -name '*.jar' ')' -exec ...

вы можете использовать find вместе с флагом-exec в одной командной строке для выполнения задания

find . -name "*.zip" -exec unzip {} \;

Что-то вроде gunzip с использованием флага-r?....

перемещение структуры каталогов рекурсивно. Если какое-либо из имен файлов, указанных в командной строке, является каталогами, gzip будет спускаться в каталог и сжимать все найденные там файлы (или распаковывать их в случае gunzip ).

http://www.computerhope.com/unix/gzip.htm


это работает отлично, как мы хотим:

распакуйте файлы:

find . -name "*.zip" | xargs -P 5 -I FILENAME sh -c 'unzip -o -d "$(dirname "FILENAME")" "FILENAME"'

выше команда не создает дубликаты папок.

удалить все zip-файлы:

find . -depth -name '*.zip' -exec rm {} \;

Если вы используете cygwin, синтаксис команды basename немного отличается.

find . -name "*.zip" | while read filename; do unzip -o -d "`basename "$filename" .zip`" "$filename"; done;

Я понимаю, что это очень старый, но это был один из первых хитов в Google, когда я искал решение чего-то подобного, поэтому я опубликую то, что я сделал здесь. Мой сценарий немного отличается, поскольку я в основном просто хотел полностью взорвать банку вместе со всеми банками, содержащимися в ней, поэтому я написал следующие функции bash:

function explode {
    local target=""
    echo "Exploding $target."
    if [ -f "$target" ] ; then
        explodeFile "$target"
    elif [ -d "$target" ] ; then
        while [ "$(find "$target" -type f -regextype posix-egrep -iregex ".*\.(zip|jar|ear|war|sar)")" != "" ] ; do
            find "$target" -type f -regextype posix-egrep -iregex ".*\.(zip|jar|ear|war|sar)" -exec bash -c 'source "<file-where-this-function-is-stored>" ; explode "{}"' \;
        done
    else
        echo "Could not find $target."
    fi
}

function explodeFile {
    local target=""
    echo "Exploding file $target."
    mv "$target" "$target.tmp"
    unzip -q "$target.tmp" -d "$target"
    rm "$target.tmp"
}

Примечание <file-where-this-function-is-stored> что необходимо, если вы храните это в файле,который не читается для неинтерактивной оболочки, как я. Если вы сохраняете функции в файле, загруженном в неинтерактивные оболочки (например,.bashrc Я считаю) вы можете отбросить все source заявление. Надеюсь, это кому-то поможет.

маленькое предупреждение - explodeFile также удаляет файл ziped, вы можете, конечно, изменить это, комментируя последнюю строку.


другим интересным решением было бы:

DESTINY=[Give the output that you intend]

# Don't forget to change from .ZIP to .zip.
# In my case the files were in .ZIP.
# The echo were for debug purpose.

find . -name "*.ZIP" | while read filename; do
ADDRESS=$filename
#echo "Address: $ADDRESS"
BASENAME=`basename $filename .ZIP`
#echo "Basename: $BASENAME"
unzip -d "$DESTINY$BASENAME" "$ADDRESS";
done;