【发布时间】:2010-03-09 06:46:16
【问题描述】:
我有包含特定模式的文件列表,但这些文件已被 tar 化。现在我想在 tar 文件中搜索模式,并在不提取文件的情况下知道哪些文件包含该模式。
任何想法...?
【问题讨论】:
标签: unix
我有包含特定模式的文件列表,但这些文件已被 tar 化。现在我想在 tar 文件中搜索模式,并在不提取文件的情况下知道哪些文件包含该模式。
任何想法...?
【问题讨论】:
标签: unix
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
【讨论】:
-x, --extract, --get:从存档中提取文件。参数是可选的。给出时,它们指定要提取的存档成员的名称。
tar's esepcially.(相关 XKCD)
zgrep 命令应该直接执行您想要的操作。
例如
zgrep "mypattern" *.gz
【讨论】:
zgrep -a pattern myfile.tar.gz
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}'"
【讨论】:
-e,但除此之外这是完美的。
grep 命令支持--label="$TAR_FILENAME";无需使用awk。
这可以通过tar --to-command 和grep --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。
【讨论】:
Python 的 tarfile module 和 Tarfile.extractfile() 将允许您检查 tarball 的内容,而无需将其解压缩到磁盘。
【讨论】:
最简单的方法可能是使用avfs。我以前用过这个来完成这样的任务。
基本上,语法是:
avfsd ~/.avfs # Sets up a avfs virtual filesystem
rgrep pattern ~/.avfs/path/to/file.tar#/
/path/to/file.tar 是实际 tar 文件的路径。
预先挂起~/.avfs/(挂载点)并附加# 让avfs 将tar 文件公开为目录。
【讨论】:
使用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 存档。
【讨论】:
您可以使用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解决了。
【讨论】: