如何在随机目录中解压缩 gz 文件并将解压后的文件存储在相同目录中?

如何在随机目录中解压缩 gz 文件并将解压后的文件存储在相同目录中?

CentOS 5.9

我有一个服务器,其中有一个 foo.ext.gz 文件位于各种随机目录中。

例子:

  • /opt/fooapp/foosubdirectory/foo_randomnumber/blah/blah/foo.ext.gz
  • /opt/fooapp/foosubdirectory/foo_ differentrandomnumber/blah/blah/foo.ext.gz
  • /opt/fooapp/foosubdirectory/foo_another Differentrandomnumber/blah/blah/foo.ext.gz

我想运行一个 bash 命令来:

  1. 找到 foo.ext.gz 文件
  2. 提取gz文件的内容在其各自的 GZ 文件所在的同一目录中
  3. 保持原始 gz 文件完整。

如果我手动执行此操作,我会从find / -iname foo.ext.gz.之后,我将复制文件所在的目录并输入如下内容:

gunzip -c /opt/fooapp/foosubdirectory/foo_12345/blah/blah/foo.ext.gz  > /opt/fooapp/foosubdirectory/foo_12345/blah/blah/foo.ext

这里的问题是我需要手动对几十个文件/目录执行此过程。

有没有办法可以利用 xargs 或 for 循环?

答案1

虽然你可以解析 a 的输出,但find你必须处理空格等。不幸的gunzip是没有--keep/-k标志来保留(就像bzip2xz一样)。

gunzipkeep如果要制作一个带有一个参数(gzip 压缩文件)并进行解压缩的小脚本,请将该脚本放在 $PATH 中的某个位置并使用以下命令调用它:

find /opt/fooapp/foosubdirectory -name "foo.ext.gz" -print0 | xargs -0 --norun-if-empty --max-args 1 gunzipkeep

该脚本可能类似于:

#!/bin/bash
inname=$1
outname=${inname%.gz}

gunzip -c "$inname" > "$outname"

答案2

如果不使用辅助脚本(或 bash 函数),很难做到这一点,就像另一个答案中所做的那样,但并非不可能。这里使用-execdir选项find和一些bash参数扩展。

find /opt/fooapp/foosubdirectory -name '*.gz' -execdir /bin/bash -c 'pwd ; echo ${0%.gz}; cp ${0} ${0%.gz}.tmp.gz ; gunzip ${0%.gz}.tmp.gz ; mv ${0%.gz}.tmp ${0%.gz}' {} \;

[编辑] 注意:您需要最新版本bash(对于此特定参数扩展),某些旧版本没有此功能。我在 V 3.2.x 上测试了这个

[编辑] 注2:-execdir据我所知,该表达式存在于 GNU find(和其他现代实现)中,但不存在于较旧的实现中。我在 GNU find v 4.2.x 上测试了这个

为了可读性和评论进行了相同的重写:

find /opt/fooapp/foosubdirectory 
     -name '*.gz'
     -execdir /bin/bash -c '_bash_command_string_ ' {} \;
# This ^ will run bash from the subdirectory containing the matched file

  _bash_command_string_  --> 
      pwd ;                       # we are working in this subdir 
      echo ${0%.gz};              # this is matched filename (minus final .gz)
      cp ${0} ${0%.gz}.tmp.gz ;   # copy the .gz file as .tmp.gz
      gunzip ${0%.gz}.tmp.gz ;    # gunzip the .tmp.gz as .tmp
      mv ${0%.gz}.tmp ${0%.gz}    # rename .tmp as matched filename (minus final .gz)

作为一个聪明的解决方案,这个解决方案很有趣,但可能太复杂而无法在实践中使用。

Bash 参考 - Shell 参数扩展, 搜索 ${parameter%word}

答案3

bash ≥4,运行shopt -s extglob递归**/遍历目录。 (请注意,这会遍历到目录的符号链接。在 zsh 中,您不需要任何特殊设置,并且**/不会下降到符号链接,但***/会下降。)然后一个简单的循环就足够了:

err=
for z in **/*.gz; do
  gunzip <"$z" >"${z%.gz}" &&
  touch -r "$z" "${z%.gz}" ||    # if you want to retain the file's modification time
  err=1
done
if [ -n "$err" ]; then echo >&1 'Watch out, there were errors!'; fi

仅使用 POSIX sh,从 调用 shell find。提取错误状态更加困难 - 检查命令是否在 stderr 上产生任何内容。

find . -name '*.gz' -exec sh -c '
  for z do gunzip <"$z" >"${z%.gz}" && touch -r "$z" "${z%.gz}"; done
' _ {} +

答案4

find . -name \*.gz | parallel gzip -dc {} \> {.}
  • {.}是没有扩展名的输入线
  • 默认分隔符只是换行符
find . -name \*.gz | while read f; do gzip -dc "$f" > "${f%.gz}"; done
  • 如果输入行可以以 IFS 中的字符开头或结尾或者是否可以包含反斜杠,则添加IFS=or-r

相关内容