我用来zgrep
搜索 tarball 文件中的字符串。如果我按照常规方式进行操作,我会得到:
aaa.tar.gz 内的 zgrep
Binary file (standard input) matches
所以我使用该-a
选项(像处理文本一样处理二进制文件)并且它确实读取了该文件,但在结果之前附加了两/三行烦人的行!
aaa.tar.gz 内的 zgrep -a
aaa.txt 0000777 0000000 0000000 00000000017 13507572577 011066 0 ustar root
root
insideinsidebbb
我怎样才能有效地删除它?
答案1
使用 GNU tar
,您可以使用该--to-command
选项将每个存档成员通过管道传输到grep
,因此(使用 GNUgrep
及其--label
选项)您还可以获得包含匹配项的嵌入文件的名称:
$ tar --to-command='grep -aH --label="$TAR_ARCHIVE[$TAR_FILENAME]" inside || true' -xf awk.tar.gz
awk.tar.gz[ytab.c]: SYNTAX("next is illegal inside a function");
awk.tar.gz[ytab.c]: SYNTAX("nextfile is illegal inside a function");
awk.tar.gz[awkgram.y]: SYNTAX("next is illegal inside a function");
awk.tar.gz[awkgram.y]: SYNTAX("nextfile is illegal inside a function");
awk.tar.gz[lex.c]:/* BUG: this ought to be inside the if; in theory could fault (daniel barrett) */
awk.tar.gz[ytabc.bak]: SYNTAX("next is illegal inside a function");
awk.tar.gz[ytabc.bak]: SYNTAX("nextfile is illegal inside a function");
这|| true
是为了避免在存档成员中找不到任何出现的情况tar: 2631: Child returned status 1
时出现警告。grep
您可以编写targrep
辅助函数或脚本,例如:
#! /bin/sh -
export PATTERN="${1?}"
shift
for file do
tar --to-command='
grep -aPH --label="$TAR_ARCHIVE[$TAR_FILENAME]" -e "$PATTERN" || true
' -xf "$file"
done
用作:
targrep inside *.tar.*
这里使用 PCRE,这是 GNU 支持的功能最齐全的正则表达式tar
,因此您可以进行不区分大小写的匹配,例如:
targrep '(?i)inside' *.tar.*
(避免在脚本中进行更复杂的选项解析来支持选项-i
)。
答案2
您得到的垃圾是 TAR 标头,因为您的 tarball 是封装在 TAR 存档中的文件,然后使用 GZIP 压缩。
grep 压缩包的最佳方法是:
tar -xzOf aaa.tar.gz | grep inside
x
: 提炼z
:存档使用 GZIP 压缩O
:输出到 stdout (假设 GNUtar
或 libarchivebsdtar
)f
:要提取的存档
您不需要 grep 的“-a”选项,因为 tar 的输出已经是纯文本(假设它只包含文本文件)。
答案3
一种方法是在 grep 之前将 NUL 字符(通常在二进制文件中分隔字符串)转换为换行符,这适用tar
于您的情况,但可能适用于其他形式的二进制文件:
file=xxx.tar.gz
zcat -f < "$file" | tr '\0' '\n' | grep -a inside