如何从 Unix 命令行递归解压目录及其子目录中的档案?

发布于 2024-07-05 13:35:51 字数 371 浏览 4 评论 0原文

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

我会发出什么命令?

重要的是,这不会因文件名中含有空格而阻塞。

The unzip command doesn't have an option for recursively unzipping archives.

If I have the following directory structure and archives:

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

And I want to unzip all of the archives into directories with the same name as each archive:

/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

What command or commands would I issue?

It's important that this doesn't choke on filenames that have spaces in them.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(12

箹锭⒈辈孓 2024-07-12 13:35:52

这对我有用

def unzip(zip_file, path_to_extract):
    """
    Decompress zip archives recursively
    Args:
        zip_file: name of zip archive
        path_to_extract: folder where the files will be extracted
    """
    try:
        if is_zipfile(zip_file):
            parent_file = ZipFile(zip_file)
            parent_file.extractall(path_to_extract)
            for file_inside in parent_file.namelist():
                if is_zipfile(os.path.join(os.getcwd(),file_inside)):
                    unzip(file_inside,path_to_extract)
            os.remove(f"{zip_file}")
    except Exception as e:
        print(e)

this works for me

def unzip(zip_file, path_to_extract):
    """
    Decompress zip archives recursively
    Args:
        zip_file: name of zip archive
        path_to_extract: folder where the files will be extracted
    """
    try:
        if is_zipfile(zip_file):
            parent_file = ZipFile(zip_file)
            parent_file.extractall(path_to_extract)
            for file_inside in parent_file.namelist():
                if is_zipfile(os.path.join(os.getcwd(),file_inside)):
                    unzip(file_inside,path_to_extract)
            os.remove(f"{zip_file}")
    except Exception as e:
        print(e)
冷夜 2024-07-12 13:35:51

Vivek Thomas 提供了很好的解决方案。 但如果你有大量数据,最好应用 -qq ,这样终端就不会完全打印出来,并放入 nohup shell 中,这样你就可以关闭终端:

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

Good solution from Vivek Thomas. But if you have a loot of data better apply -qq so the terminal does not get fully printed and put in a nohup shell so you can close the terminal:

nohup find . -name "*.zip" | xargs -P 5 -I fileName sh -c 'unzip -qq -o -d "$(dirname "fileName")/$(basename -s .zip "fileName")" "fileName"' &
情痴 2024-07-12 13:35:51

您还可以循环遍历每个 zip 文件,创建每个文件夹并解压缩该 zip 文件。

for zipfile in *.zip; do
  mkdir "${zipfile%.*}"
  unzip "$zipfile" -d "${zipfile%.*}"
done

You can also loop through each zip file creating each folder and unzip the zip file.

for zipfile in *.zip; do
  mkdir "${zipfile%.*}"
  unzip "$zipfile" -d "${zipfile%.*}"
done
ゞ记忆︶ㄣ 2024-07-12 13:35:51

另一个有趣的解决方案是:

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;

Another interesting solution would be:

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;
凤舞天涯 2024-07-12 13:35:51

我意识到这已经很老了,但当我在寻找类似问题的解决方案时,它是 Google 上的第一批点击之一,所以我将在这里发布我所做的事情。 我的场景略有不同,因为我基本上只是想完全爆炸一个 jar 以及其中包含的所有 jar,因此我编写了以下 bash 函数:

function explode {
    local target="$1"
    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="$1"
    echo "Exploding file $target."
    mv "$target" "$target.tmp"
    unzip -q "$target.tmp" -d "$target"
    rm "$target.tmp"
}

注意 ; 如果您将其存储在一个文件中,而该文件不能像我一样为非交互式 shell 读取,则需要使用该文件。 如果您将函数存储在非交互式 shell 上加载的文件中(例如,我相信是 .bashrc),您可以删除整个 source 语句。 希望这会对某人有所帮助。

一个小警告 - explodeFile 还会删除压缩文件,您当然可以通过注释掉最后一行来更改它。

I realise this is very old, but it was among the first hits on Google when I was looking for a solution to something similar, so I'll post what I did here. My scenario is slightly different as I basically just wanted to fully explode a jar, along with all jars contained within it, so I wrote the following bash functions:

function explode {
    local target="$1"
    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="$1"
    echo "Exploding file $target."
    mv "$target" "$target.tmp"
    unzip -q "$target.tmp" -d "$target"
    rm "$target.tmp"
}

Note the <file-where-this-function-is-stored> which is needed if you're storing this in a file that is not read for a non-interactive shell as I happened to be. If you're storing the functions in a file loaded on non-interactive shells (e.g., .bashrc I believe) you can drop the whole source statement. Hopefully this will help someone.

A little warning - explodeFile also deletes the ziped file, you can of course change that by commenting out the last line.

相守太难 2024-07-12 13:35:51

如果您使用 cygwin,则 basename 命令的语法略有不同。

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

If you're using cygwin, the syntax is slightly different for the basename command.

find . -name "*.zip" | while read filename; do unzip -o -d "`basename "$filename" .zip`" "$filename"; done;
内心旳酸楚 2024-07-12 13:35:51

像gunzip 使用 -r 标志之类的东西?......

递归地遍历目录结构。 如果命令行上指定的任何文件名是目录, gzip 将下降到该目录并压缩它在其中找到的所有文件(或者在gunzip的情况下解压缩它们)。

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

Something like gunzip using the -r flag?....

Travel the directory structure recursively. If any of the file names specified on the command line are directories, gzip will descend into the directory and compress all the files it finds there (or decompress them in the case of gunzip ).

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

九厘米的零° 2024-07-12 13:35:51

这完全符合我们的要求:

解压缩文件:

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

以上命令不会创建重复的目录。

删除所有 zip 文件:

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

This works perfectly as we want:

Unzip files:

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

Above command does not create duplicate directories.

Remove all zip files:

find . -depth -name '*.zip' -exec rm {} \;
罪#恶を代价 2024-07-12 13:35:51

您可以在单个命令行中使用 find 和 -exec 标志来完成这项工作

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

You could use find along with the -exec flag in a single command line to do the job

find . -name "*.zip" -exec unzip {} \;
谷夏 2024-07-12 13:35:51

如果您想将文件提取到相应的文件夹,您可以尝试这个适用于

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

可以处理高 I/O 的系统的多处理版本:

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

If you want to extract the files to the respective folder you can try this

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

A multi-processed version for systems that can handle high I/O:

find . -name "*.zip" | xargs -P 5 -I fileName sh -c 'unzip -o -d "$(dirname "fileName")/$(basename -s .zip "fileName")" "fileName"'
随遇而安 2024-07-12 13:35:51

正确处理所有文件名(包括换行符)并提取到与文件位于同一位置的目录中的解决方案,只需删除扩展名:

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

请注意,您可以轻松地使其处理更多文件类型(例如 .jar),通过使用 -o 添加它们,例如:

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

A solution that correctly handles all file names (including newlines) and extracts into a directory that is at the same location as the file, just with the extension removed:

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

Note that you can easily make it handle more file types (such as .jar) by adding them using -o, e.g.:

find . '(' -iname '*.zip' -o -iname '*.jar' ')' -exec ...
往日情怀 2024-07-12 13:35:51

这是一种将所有 zip 文件提取到工作目录的解决方案,并涉及 find 命令和 while 循环:

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

Here's one solution that extracts all zip files to the working directory and involves the find command and a while loop:

find . -name "*.zip" | while read filename; do unzip -o -d "`basename -s .zip "$filename"`" "$filename"; done;
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文