标准grep
/pcregrep
等可以方便地用于ASCII或UTF8数据的二进制文件 - 是否有一个简单的方法,使他们也尝试UTF16也(最好是同时,但会做)?grepping二进制文件和UTF16
数据我试图得到的是所有的ASCII无论如何(在图书馆等参考),它只是不会被发现,因为有时有两个字符之间有00,有时并没有。
我没有看到任何方式让它在语义上完成,但这些00应该做的伎俩,除非我不能轻松地在命令行上使用它们。
标准grep
/pcregrep
等可以方便地用于ASCII或UTF8数据的二进制文件 - 是否有一个简单的方法,使他们也尝试UTF16也(最好是同时,但会做)?grepping二进制文件和UTF16
数据我试图得到的是所有的ASCII无论如何(在图书馆等参考),它只是不会被发现,因为有时有两个字符之间有00,有时并没有。
我没有看到任何方式让它在语义上完成,但这些00应该做的伎俩,除非我不能轻松地在命令行上使用它们。
最简单的方法是只转换文本文件为UTF-8和管道将到grep:
iconv -f utf-16 -t utf-8 file.txt | grep query
我试图做的相反(转换我的查询为UTF-16),但它似乎虽然grep不喜欢那样。我认为这可能与排序有关,但我不确定。
似乎grep会将utf-16的查询转换为utf-8/ascii。这里是我的尝试:
grep `echo -n query | iconv -f utf-8 -t utf-16 | sed 's/..//'` test.txt
如果test.txt的是UTF-16文件,这是不行的,但它的工作,如果test.txt的是ASCII。我只能得出结论,grep正在将我的查询转换为ascii。
编辑:这里是一个非常真的疯了一个那样的作品,但不会给你很多有用的信息:
hexdump -e '/1 "%02x"' test.txt | grep -P `echo -n Test | iconv -f utf-8 -t utf-16 | sed 's/..//' | hexdump -e '/1 "%02x"'`
它是如何工作的?那么它将您的文件转换为十六进制(不需要任何额外的格式,通常使用hexdump)。它将其转换为grep。 Grep使用通过将你的查询(不带换行符)回显到iconv中的查询来将它转换为utf-16。然后将其输入sed以删除BOM(用于确定排序的utf-16文件的前两个字节)。然后将其传送到hexdump中,以便查询和输入相同。
不幸的是我认为如果只有一个匹配,这将最终打印出整个文件。如果二进制文件中的utf-16以不同于您机器的字节顺序存储,这也不起作用。
EDIT2:明白了!!!!
grep -P `echo -n "Test" | iconv -f utf-8 -t utf-16 | sed 's/..//' | hexdump -e '/1 "x%02x"' | sed 's/x/\\\\x/g'` test.txt
此搜索文件test.txt
'iconv'不会起作用,因为它是一个非二进制文件,很多非UTF-16数据,'iconv'在第一个错误时退出。 – taw 2010-09-24 13:27:40
哎哟......我还在寻找到给grep的一个UTF-16查询出于好奇心(我不认为它的转换,因为它并没有真正知道的编码,它得是做别的事情奇怪)和我如果我想出点什么,我会让你知道的。 – 2010-09-24 14:23:09
看看我的编辑。有什么工作。 – 2010-09-24 15:58:57
战略经济对话语句是超过了我能绕到我的头在字符串Test
(以UTF-16)的十六进制版本。我有一个简单的,远从完美的TCL脚本,我觉得做一个好工作与我的一个测试点:
#!/usr/bin/tclsh
set insearch [lindex $argv 0]
set search ""
for {set i 0} {$i<[string length $insearch]-1} {incr i} {
set search "${search}[string range $insearch $i $i]."
}
set search "${search}[string range $insearch $i $i]"
for {set i 1} {$i<$argc} {incr i} {
set file [lindex $argv $i]
set status 0
if {! [catch {exec grep -a $search $file} results options]} {
puts "$file: $results"
}
}
我用这一个所有的时间倾倒Windows注册表作为其输出是unicode后。这是在Cygwin下运行的。
$ regedit /e registry.data.out
$ file registry.data.out
registry.data.out: Little-endian **UTF-16 Unicode text**, with CRLF line terminators
$ sed 's/\x00//g' registry.data.out | egrep "192\.168"
"Port"="192.168.1.5"
"IPSubnetAddress"="192.168.189.0"
"IPSubnetAddress"="192.168.102.0"
[HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\Print\Monitors\Standard TCP/IP Port\Ports\192.168.1.5]
"HostName"="192.168.1.5"
"Port"="192.168.1.5"
"LocationInformation"="http://192.168.1.28:1215/"
"LocationInformation"="http://192.168.1.5:80/WebServices/Device"
"LocationInformation"="http://192.168.1.5:80/WebServices/Device"
"StandaloneDhcpAddress"="192.168.173.1"
"ScopeAddressBackup"="192.168.137.1"
"ScopeAddress"="192.168.137.1"
"DhcpIPAddress"="192.168.1.24"
"DhcpServer"="192.168.1.1"
"0.0.0.0,0.0.0.0,192.168.1.1,-1"=""
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Print\Monitors\Standard TCP/IP Port\Ports\192.168.1.5]
"HostName"="192.168.1.5"
"Port"="192.168.1.5"
"LocationInformation"="http://192.168.1.28:1215/"
"LocationInformation"="http://192.168.1.5:80/WebServices/Device"
"LocationInformation"="http://192.168.1.5:80/WebServices/Device"
"StandaloneDhcpAddress"="192.168.173.1"
"ScopeAddressBackup"="192.168.137.1"
"ScopeAddress"="192.168.137.1"
"DhcpIPAddress"="192.168.1.24"
"DhcpServer"="192.168.1.1"
"0.0.0.0,0.0.0.0,192.168.1.1,-1"=""
"MRU0"="192.168.16.93"
[HKEY_USERS\S-1-5-21-2054485685-3446499333-1556621121-1001\Software\Microsoft\Terminal Server Client\Servers\192.168.16.93]
"A"="192.168.1.23"
"B"="192.168.1.28"
"C"="192.168.1.200:5800"
"192.168.254.190::5901/extra"=hex:02,00
"00"="192.168.254.190:5901"
"ImagePrinterPort"="192.168.1.5"
我想这种方式有误报的机会渺茫,但它可能什么都想的99.9%。它也适用于MINGW64 Git Bash。 – mwfearnley 2017-07-10 14:45:31
我将此添加为上面接受的答案的评论,但为了便于阅读。这使您可以搜索一堆文件中的文本,同时显示正在查找文本的文件名。所有这些文件都有.reg扩展名,因为我正在搜索导出的Windows注册表文件。只需用任何文件扩展名替换.reg。
// Define grepreg in bash by pasting at bash command prompt
grepreg()
{
find -name '*.reg' -exec echo {} \; -exec iconv -f utf-16 -t utf-8 {} \; | grep "$1\|\.reg"
}
// Sample usage
grepreg SampleTextToSearch
可明确包含在搜索字符串中的空白(00秒),但你会得到的结果与空值,所以你可能需要将输出重定向到一个文件,以便你可以看看它有一个合理的编辑器,或者通过sed管道来替换空值。要搜索* .utf16.txt“吧”:
grep -Pa "b\x00a\x00r" *.utf16.txt | sed 's/\x00//g'
“-P”是告诉grep来接受Perl的正则表达式的语法,这使得\ X00扩展到零,和-a告诉它忽略Unicode看起来像二进制的事实。
好技术,我没想到这个。 grep的'-a'标志在这里是非常神奇的。假定你没有大文件要搜索(在这种情况下这可能太慢),只需指定'.'而不是'\ x00',就可以使输入变得更简单。 '.'将匹配任何内容,而不仅仅是空值。这可能并不总是你想要的,但可能大部分时间都可以。通常,清除空值的sed也不是必需的 - 它们不会输出任何内容。所以对于你的例子,只需'grep -a b.a.r * .utf16.txt'应该可以工作。 – 2015-12-23 22:11:41
我需要递归地做到这一点,这是我想出了:
find -type f | while read l; do iconv -s -f utf-16le -t utf-8 "$l" | nl -s "$l: " | cut -c7- | grep 'somestring'; done
这绝对是可怕的,非常慢;我敢肯定有一个更好的方法,我希望有人能改善它 - 但我很着急:P
什么片做:
find -type f
给出的文件名与路径的递归列表相对于电流
while read l; do ... done
Bash loop;对于文件路径列表中的每一行,将路径放入$l
并在循环中执行该操作。 (为什么我使用shell循环而不是xargs,这会更快:我需要在输出的每一行前加上当前文件的名称。如果我正在喂食,想不到这样做的方法一次多个文件的iconv,并且因为我将要在同一时间做反正一个文件,外壳环是比较容易的语法/转义)
iconv -s -f utf-16le -t utf-8 "$l"
转换在$l
命名的文件:假设输入文件是utf-16小端,并将其转换为utf-8。 -s
使iconv关闭任何转换错误(会有很多,因为这个目录结构中的某些文件不是utf-16)。此转换的输出转到stdout。
nl -s "$l: " | cut -c7-
这是一个黑客:nl
插入行号,却偏偏有一个“使用任意字符串来分隔行数”参数,所以我把文件名(后跟冒号和空格)在那里面。然后我使用cut
去除行号,只留下文件名前缀。 (为什么我没有使用sed
:这种方式更容易转义,如果我使用sed表达式,我不得不担心文件名中有正则表达式字符,在我的情况下有很多。nl
是多少比sed
,并且将只取参数-s
完全从字面上看,和外壳处理逃逸我。)
因此,通过这条管道的终点,我已经转换一堆文件为UTF-8的线,以文件名为前缀,然后我grep。如果有匹配,我可以从前缀中知道他们在哪个文件中。
注意事项
grep -R
慢得多,因为我产卵iconv
,nl
,cut
,并grep
新副本的每一个文件。这太糟糕了。grep -R
以及作为这个命令(如果你有多个unicode编码类型,比如一些big-endian和一些little-endian文件,你需要调整这个命令并为每个不同的编码重新运行它)。完全恶心。和veeeery有帮助。 thx – 2017-03-24 12:05:32
我不得不做'找。 -type f'在OS X上 – 2017-08-24 22:39:34
我发现下面的解决方案为我工作最好的,从https://www.splitbits.com/2015/11/11/tip-grep-and-unicode/
grep的不使用Unicode发挥出色,但它可以到处工作。例如,要查找,
Some Search Term
在UTF-16文件,使用正则表达式忽略每个字符的第一个字节,
S.o.m.e. .S.e.a.r.c.h. .T.e.r.m
还有,告诉grep来处理该文件为文本,使用'-a',最后的命令看起来像这样,
grep -a 'S.o.m.e. .S.e.a.r.c.h. .T.e.r.m' utf-16-file.txt
......如果字符长度是两个字节,它不是ASCII。 – 2010-09-20 15:28:27
我的意思是ASCII字符范围(U + 0000到U + 007F),而不是ASCII编码。 – taw 2010-09-20 20:27:02