【问题标题】:How do I grep GZ files to extract PNG files?如何 grep GZ 文件以提取 PNG 文件?
【发布时间】:2015-06-15 19:28:11
【问题描述】:

好的,所以我在一个文件夹中有一个 .GZ 文件的基调,我希望递归地查看每个文件并将所有 PNG 文件提取到另一个目标文件夹中。我该怎么做?

编辑:

我一直在终端使用此命令在 GZ 文件中查找字符串并将整个文件复制到另一个目标目录。然后用它做事。有一些缺点。一,当我输入“PNG”时,它会找到引用“PNG”而不是文件类型的CSS文件等文件。其次,除了复制整个文件之外,它不会向目录输出任何内容。我想提取文件。

find . -type f -print0 | xargs -0 grep -lh "png" | xargs -I % cp % /some_destination

编辑:

这是一个示例文件夹结构:

FILE001.GZ、FILE002.GZ、FILE003.GZ等

并非所有文件都包含 PNG,其中一些文件在文件夹结构中包含许多文件。我想要的是另一个目标文件夹中的以下内容:

34950560.png、3959560.png等

提前谢谢你!

【问题讨论】:

  • gz 只包含一个文件,所以只需查找foo.png.gz。如果它们是 tar 文件,则不能。文件名在 tar 中,现在已压缩,您无法弄清楚 png 在压缩后的 tar 中变成了哪些随机字节。换句话说,您将解压缩每个 tar 文件并列出其中的文件。
  • 它们都是gz文件,所以tar问题不是问题。我没有按照你的意思寻找 foo.png.gz 吗?提前感谢您的帮助。
  • find . -name \*.png.gz。完成
  • 不,不是这样。
  • 如果它们包含“实体文件夹结构”,那么它们就不是普通的 gz 文件。他们必须是 tar.gz

标签: grep png gzip


【解决方案1】:

假设您的“.GZ”文件实际上是包含多个文件的“.tar”压缩包,那么您可以在一行中完成您的目标:

find . -type f -iname '*.GZ' | xargs -n1 -I'{}' tar -C "/path/to/extract" -xf '{}' '*.png' 2>/dev/null

解释:

  • find . -type f -iname '*.GZ' :在当前路径(包括子目录)中查找所有 .GZ 文件。 -iname 表示不区分大小写,同时匹配 .gz 和 .GZ 文件
  • xargs -n1 -I'{}' <command> '{}' :从标准输入调用“命令”,最多带有一个参数 (-n1),将参数放在占位符 {} 中。
  • tar -C "/path/to/extract" -xf '{}' '*.png' :从 xargs (-xf {}) 获得的文件中提取,只有以 '*.png' 结尾的文件。 -C /path/to/extract:在那里提取文件。
  • 2>/dev/null :将不包含 .png 文件的 GZ 文件引发的错误消息静音。

此命令将提取指定文件夹中的所有 .png 文件(保留原始 tar.gz 文件中的所有目录结构)。跨多个档案的同名 .png 文件将仅存储一次,即最后提取的 .png 文件将覆盖以前的同名文件。 如果你想克服这个问题,那么你需要一个更复杂的脚本,比如:

#!/usr/bin/bash

function extract_png() {
    local gzpath=$1; local extract_path=$2
    cd "$gzpath" || return 2
    find . -iname '*.GZ' | 
        while read gzfile; do
            if tar -tf "$gzfile" '*.png' 2>/dev/null; then
                local basename=${gzfile%.*}; basename=${basename##*/}
                local extract_to="$extract_path/$basename"
                mkdir -p "${extract_to}"
                tar -C "$extract_to" -xf "$gzfile" '*.png'
            fi
        done
}

extract_png '/path/to/search' '/path/to/save'

extract_png 函数会将提取的.png 文件保存到每个存档的不同子文件夹中,位于/path/to/save 下(例如/path/to/save/FILE001//path/to/save/FILE002/ 等)。

关于if tar -tf "$gzfile" '*.png' 2>/dev/null; then ... 的解释:如果文件“$gzfile”中有.png 文件,这将返回true。 tar 中的 -t 参数表示“列表内容”。当指定文件 (*.png) 未包含在存档中时,tar -t 会打印一条错误消息(由 2>/dev/null 隐藏)并返回一个非零代码,该代码将此条件评估为 false。

【讨论】:

  • 太棒了,多么完整的答案!几分钟后我要试试这个!
  • 很高兴它有帮助。请注意,您也可以将上述内容调整为其他文件类型(例如*.jpeg),只需更改相应的参数即可。
【解决方案2】:

您可以使用文件签名(又名幻数)。 PNG 文件的前几个字节包含一个文件签名,以表明该文件是 PNG。如果这些文件都是 gzip 文件,那么 gzip 会有一个额外的标头,我们可以跳过它。
od 是一个命令,它将以您指定的可读格式转储文件的一部分。我告诉它跳过 gzip 标头并以十六进制格式转储。根据我的测试,接下来的八个字节将得到一个字符串“34e6 5580”。如果它与 PNG 签名匹配,则将其移动到新目录并重命名。

COUNTER=0; mkdir PNGDIR
#
for FILE in `ls -1d *`; do  
   od -j 4 -N 10 -x ${FILE} | grep -q "34e6 5580" 
   if [ $? -eq 0 ]; then
     COUNTER=`expr 1 + $COUNTER`
     cp ${FILE} PNGDIR/picture_${COUNTER}.png.gz
   fi
done

【讨论】:

  • 那么代码放在 BASH 文件中? .sh 文件,对吗?
  • 当然,如果你喜欢的话。您也可以将其复制并粘贴到命令行中。
  • 很棒的答案。我把它给了另一个人,因为它是最完整的,但你肯定很好地回答了这个问题。
  • 谢谢,WB。很高兴你得到了对你有用的东西。这也是一些好看的代码。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-03-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多