如何递归提取文件但将它们保留在自己的文件夹中?

如何递归提取文件但将它们保留在自己的文件夹中?

这就是我提取文件夹中所有文件的方式(递归):

find -iname \*.epub -exec unzip -o {} \;

但提取的文件最终全部位于父文件夹中:

Parent (Extracted Epub files)
  Child (Epub files)
  Child (Epub files)

如何更改该命令,以便将它们提取到自己的文件夹中?

Parent
  Child (Epub files and extracted Epub files)
  Child (Epub files and extracted Epub Files)

答案1

如果您使用 GNU find,请使用其-execdir操作:

find -iname \*.epub -execdir unzip -o {} \;

这将从找到文件的每个目录运行unzip,确保将文件提取到适当的子目录中。

如果您指定起始目录,这至少也适用于某些 BSD(特别是 OpenBSD):

find /path/to/start -iname \*.epub -execdir unzip -o -- {} \;

答案2

斯蒂芬·基特的-execdir回答很好,如果多个文件可能.epub位于同一目录中(所以-execdir没有帮助),您需要执行以下操作:

find ./ -iname '*.epub' -exec sh -c '
  for f; do
    rp="$(realpath -e "$f")"
    bn="$(basename "$f" .epub)"
    dn="$(dirname "$rp")/$bn"

    [ -e "$dn" ] && continue
    echo mkdir -p "$dn"
    echo unzip -d "$dn" -o "$rp"
  done' find-sh {} +

"$f"对于传递给 sh 脚本的每个参数 ( ),它用于realpath将其完整绝对路径名获取到变量中rpbasename然后用于将不带 .epub 扩展名的基本文件名获取到变量中bndirname用于获取绝对目录名称,并"/$bn"附加给我们变量dn。顺便说一句,所有这三个程序都在 GNU 中核心工具

如果"$dn"已经存在,则在语句中跳过它continue(如果需要,这将是添加更多错误检查和错误处理代码的好地方)。否则,它是通过mkdir -punzip 选项创建并用作参数的-d"$rp"用作 的文件名 arg unzip

注意:这是作为试运行编写的,因此它只打印它所要的内容做,但没有真正做。从命令中删除echo语句以使其实际创建目录并将 .epub 文件提取到其中。

您可能需要添加echo "$rp"orecho "$f"语句并使用unzip's-q选项来减少输出的噪音量,同时在迭代文件名时仍显示进度。

答案3

使用 GNUsedfind支持现在常见(尽管不是标准)-iname/-print0谓词的实现,您可以执行以下操作:

LC_ALL=C find . -iname '?*.epub' \
              ! -name '*[[*?]*' \
              ! -iname ..epub \
              ! -iname ...epub \
                -type f -print0 |
  LC_ALL=C sed -z 'h;s/\.epub$//;p;g' |
  xargs -r0n2 unzip -d

(跳过包含[,*?字符的文件名,以解决unzip将它们视为通配符以查找匹配文件的错误功能)。

哪个会运行

unzip -d ./path/to/file ./path/to/file.epub

将文件内容解压epub到以文件命名的目录中,不带扩展名。

我们还跳过.epub?*之前需要至少一个字节...epub...epub文件,因为相应的目录将是""...将是一个问题。

或者使用 zsh:

set -o extendedglob
for f (./**/(^*[[*?]*).(#i)epub(N.)) unzip -d $f:r $f

./**/(^(|.|..|*[[?*]*)).(#i)epub(ND.)这里省略隐藏的,如果需要的话将 glob 更改为(再次排除.epub, ..epub, ...epub)。

有了,我们可以通过替换为, with ...来更好地解决, ,字符的zsh问题。[?**[*]?[?]

set -o extendedglob
for f (./**/*.(#i)epub(N.)) unzip -d $f:r $f:h/${${f:t}//(#m)[[?*]/[$MATCH]}

或者您可以使用更 Unixy 的命令来提取 zip 存档,例如 libarchive 的bsdtar

set -o extendedglob
for f (**/*.(#i)epub(N.)) {
  mkdir -p -- $f:r && bsdtar -C $f:r -xf $f
}

或者,使用find并包含隐藏的:

LC_ALL=C find . -iname '?*.epub' ! -iname ..epub ! -iname ...epub -exec sh -c '
  for file do
    dir=${file%.*}
    mkdir -p "$dir" &&
      bsdtar -C "$dir" -xf "$file"
  done' sh {} +

相关内容