【问题标题】:Performing grep operation in tar files without extracting在 tar 文件中执行 grep 操作而不提取
【发布时间】:2010-03-09 06:46:16
【问题描述】:

我有包含特定模式的文件列表,但这些文件已被 tar 化。现在我想在 tar 文件中搜索模式,并在不提取文件的情况下知道哪些文件包含该模式。

任何想法...?

【问题讨论】:

标签: unix


【解决方案1】:

tar 命令有一个-O 开关,用于将文件提取到标准输出。因此,您可以将这些输出通过管道传输到 grep/awk

tar xvf  test.tar -O | awk '/pattern/{print}'

tar xvf  test.tar -O | grep "pattern"

例如返回文件名找到的一种模式

tar tf myarchive.tar | while read -r FILE
do
    if tar xf test.tar $FILE  -O | grep "pattern" ;then
        echo "found pattern in : $FILE"
    fi
done

【讨论】:

  • 不幸的是,它不会给出匹配文件的名称。
  • 因此,在归档文件之后将其中一个 tar 文件的名称提供给 tar 仅给出该文件的内容!这是在哪里记录的?你能告诉我吗?
  • @AnkurAgarwal In the manpage -- -x, --extract, --get:从存档中提取文件。参数是可选的。给出时,它们指定要提取的存档成员的名称。
  • @AnkurAgarwal 诚然,man pages 是著名的hard to understandtar's esepcially.(相关 XKCD)
【解决方案2】:

zgrep 命令应该直接执行您想要的操作。

例如

zgrep "mypattern" *.gz

http://linux.about.com/library/cmd/blcmdl1_zgrep.htm

【讨论】:

  • 这个问题是关于 tar 文件,而不是 gzip 文件。
  • zgrep -a pattern myfile.tar.gz
【解决方案3】:

GNU tar--to-command。有了它,您可以让tar 将存档中的每个文件通过管道传输到给定的命令中。对于您只想要匹配的行的情况,该命令可以是简单的grep。要知道文件名,您需要利用 tar 在命令环境中设置某些变量;例如,

tar xaf thing.tar.xz --to-command="awk -e '/thing.to.match/ {print ENVIRON[\"TAR_FILENAME\"] \":\", \$0}'"

因为我发现自己经常使用这个,所以我有这个:

#!/bin/sh
set -eu

if [ $# -lt 2 ]; then
    echo "Usage: $(basename "$0") <pattern> <tarfile>"
    exit 1
fi

if [ -t 1 ]; then
    h="$(tput setf 4)"
    m="$(tput setf 5)"
    f="$(tput sgr0)"
else
    h=""
    m=""
    f=""
fi

tar xaf "$2" --to-command="awk -e '/$1/{gsub(\"$1\", \"$m&$f\"); print \"$h\" ENVIRON[\"TAR_FILENAME\"] \"$f:\", \$0}'"

【讨论】:

  • 我的 awk 不接受 -e,但除此之外这是完美的。
  • grep 命令支持--label="$TAR_FILENAME";无需使用awk
【解决方案4】:

这可以通过tar --to-commandgrep --label 来完成:

tar xaf archive.tar.gz --to-command 'egrep -Hn --label="$TAR_FILENAME" your_pattern_here || true'
  • --label 给 grep 文件名
  • -H 告诉 grep 显示文件名,-n 显示行号
  • || true 因为如果找不到模式,grep 将退出并出现错误,tar 会抱怨。
  • xaf 表示解压,根据文件扩展名自动解压
  • --to-command 让 tar 将 tarfile 中的每个文件传递给单独的 grep 调用,并使用有关文件的信息设置各种环境变量。请参阅the manpage 了解更多信息。

很大程度上基于Chipaca's answer(和 Daniel H 的评论),但这应该更容易使用,只使用 tar 和 grep。

【讨论】:

    【解决方案5】:

    Python 的 tarfile moduleTarfile.extractfile() 将允许您检查 tarball 的内容,而无需将其解压缩到磁盘。

    【讨论】:

      【解决方案6】:

      最简单的方法可能是使用avfs。我以前用过这个来完成这样的任务。

      基本上,语法是:

      avfsd ~/.avfs # Sets up a avfs virtual filesystem
      rgrep pattern ~/.avfs/path/to/file.tar#/
      

      /path/to/file.tar 是实际 tar 文件的路径。

      预先挂起~/.avfs/(挂载点)并附加# 让avfs 将tar 文件公开为目录。

      【讨论】:

        【解决方案7】:

        使用ugrep 选项-z 实际上非常简单:

        -z, --decompress
                Decompress files to search, when compressed.  Archives (.cpio,
                .pax, .tar, and .zip) and compressed archives (e.g. .taz, .tgz,
                .tpz, .tbz, .tbz2, .tb2, .tz2, .tlz, and .txz) are searched and
                matching pathnames of files in archives are output in braces.  If
                -g, -O, -M, or -t is specified, searches files within archives
                whose name matches globs, matches file name extensions, matches
                file signature magic bytes, or matches file types, respectively.
                Supported compression formats: gzip (.gz), compress (.Z), zip,
                bzip2 (requires suffix .bz, .bz2, .bzip2, .tbz, .tbz2, .tb2, .tz2),
                lzma and xz (requires suffix .lzma, .tlz, .xz, .txz).
        

        例如:

        ugrep -z PATTERN archive.tgz
        

        这 greps 每个存档文件以显示 PATTERN 与存档文件名匹配。存档文件名显示在大括号中,以区别于普通文件名。其他一切都与grep 相同(ugrep 具有相同的选项并产生相同的输出)。例如:

        $ ugrep -z "Hello" archive.tgz
        {Hello.bat}:echo "Hello World!"
        Binary file archive.tgz{Hello.class} matches
        {Hello.java}:public class Hello // prints a Hello World! greeting
        {Hello.java}:  { System.out.println("Hello World!");
        {Hello.pdf}:(Hello)
        {Hello.sh}:echo "Hello World!"
        {Hello.txt}:Hello
        

        如果您只想要文件名,请使用选项 -l (--files-with-matches) 并使用选项 --format="%z%~" 自定义文件名输出以摆脱大括号:

        $ ugrep -z Hello -l --format="%z%~" archive.tgz
        Hello.bat
        Hello.class
        Hello.java
        Hello.pdf
        Hello.sh
        Hello.txt
        

        搜索压缩包(.tar.gz/.tgz.tar.bz2/.tbz.tar.xz/.txz.tar.lzma/.tlz)以及 .zip 存档。

        【讨论】:

          【解决方案8】:

          您可以使用ratarmount 挂载 TAR 存档,然后只需在挂载视图中搜索模式:

          pip install --user ratarmount
          ratarmount large-archive.tar mountpoint
          grep -r '<pattern>' mountpoint/
          

          这应该比遍历每个文件并将其打印到标准输出要快得多,尤其是对于压缩的 TAR。


          这是一个简单的比较基准:

          function checkFilesWithRatarmount()
          {
              local pattern=$1
              local archive=$2
              ratarmount "$archive" "$archive.mountpoint"
              'grep' -r -l "$pattern" "$archive.mountpoint/"
          }
          
          function checkEachFileViaStdOut()
          {
              local pattern=$1
              local archive=$2
              tar --list --file "$archive" | while read -r file; do
                  if tar -x --file "$archive" -O -- "$file" | grep -q "$pattern"; then
                      echo "Found pattern in: $file"
                  fi
              done
          }
          
          function createSampleTar()
          {
              for i in $( seq 40 ); do 
                  head -c $(( 1024 * 1024 )) /dev/urandom | base64 > $i.dat
              done
              tar -czf "$1" [0-9]*.dat
          }
          
          createSampleTar myarchive.tar.gz
          time checkEachFileViaStdOut ABCD myarchive.tar.gz
          time checkFilesWithRatarmount ABCD myarchive.tar.gz
          sleep 0.5s
          fusermount -u myarchive.tar.gz.mountpoint
          

          包含 40 个文件的 55 MiB 未压缩和 42 MiB 压缩 TAR 存档在几秒钟内生成:

          Compression Ratarmount Bash Loop over tar -O
          none 0.31 +- 0.01 0.55 +- 0.02
          gzip 1.1 +- 0.1 13.5 +- 0.1
          bzip2 1.2 +- 0.1 97.8 +- 0.2

          当然,这些结果很大程度上取决于存档大小和存档包含的文件数量。这些测试示例非常小,因为我不想等待太久,但它们已经显示了问题。文件越多,tar -O 跳转到正确文件所需的时间就越长。对于压缩档案,档案大小越大,它的二次方速度就越慢,因为必须解压缩请求文件之前的所有内容,并且单独请求每个文件。这两个问题都被ratarmount解决了。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2017-12-13
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2013-02-23
            相关资源
            最近更新 更多