如何使用 shell 脚本读取其中包含一些文本字符串的二进制文件?

How to read a binary file which has some text string in it in using shell script?

我有一个名为 142490.1 的文件,该文件的内容如下 -

^A^A^@^@^@=^@^@=y^B^@e^A^C^@f^B^H¬^\ÂA^Y^A^G^B<81>s
^A^@G@client.1424906160996.30431.DC1.5faa5c2a-c382-40b8-baa8-234a8e6ecd19^@^@^A^F<8b>f^@ø^@y^@^@^AKÃ^F<86>T^@^@^@êõ^A\^@^R304344351^N2047675^@^D77^@^Y^W^B^@
27.99^@^X261449949761^@Ã^O^@<92>^NICHOLSON Baseball     ^V|t -S M L XL XXL(2)^@
15724^@
63862^U^GðV11450^@^B7^@<9a>^A^@^L823196^@¨<99>´°øR^B^@^TBj%2FRZUw*^@^PBoZf8jU*^@^T1032869222^B^@&LH_DefaultDomain_77^@^@^A^@^@H@client.1424906160992.116975.DC1.344073e8-93f6-487c-b343-7923080f07aa^@^@^AKÃ^F<8b>f^@­^@y^@^@^AKÃ^Eò<9f>£^AX^@^T1169755138^N2047935^@^B3.^W^@ð^?^B^@^H0.99^@^X171689807229^B^@rTOPSHOP LEATHER 3 EU 36^B^B^@
45333^B^B^@^F^@^L161103^@ðï°øR^B^B^@^PBosZQlE*^B^B^B^@^@^A^@^@G@client.1424906160976.1295684.DC1.66a6ca77-30ee-4d50-b7ea-4a524eb94af1^@^@^AKÃ^F<8b>f^@¤^@y^@^@^AKÃ^F<89>^O^@^@^@<96><9a>^AT^@^R129569484^N2047935^@^B3^]^V^B^@^F499^853759648^B^@bWILLIS AND^B^B^@
20489^B^B^@^F^@^P-1404420^@<9e>¤´°øR^B^B^@^PBop4ml0*^B^B^B^@^@^A^@^@H@client.1424906160989.104826.DC1.4d58c06a-3526-408a-a48b-8bdc82b94dba^@^@^AKÃ^F<8b>f^@¨^@R^@^@^AKÃ^F<83>¶^@^@^@<9a>·^AX^@^T1048328026^N2045573^@^B0.^W^@^P^B^B^^Að@^@^H6000^@^Z1955 corvette^@ì<8e>´°øR^B^@^PBiZzFm8*^@^PBoO8YKc*^@^@^A^@

我知道上面的文件内容看起来主要是二进制文件,但是文件中有一些我们可以清楚地读取的字符串。

如果你看到上面的文件内容,你会看到这样一个字符串 -

@client.1424906160996.30431.DC1.5faa5c2a-c382-40b8-baa8-234a8e6ecd19

上面的字符串中1424906160996是一个时间戳。

问题陈述:

我需要找到所有以 @client 开头且其时间戳比当前时间戳早一分钟的字符串。

假设下面是以 @client 开头的字符串,并且其时间戳比当前时间戳早一分钟,那么在读取文件后它应该像这样打印出来 -

@client.1424906161996.3031.DC1.5faaa-c382-40b8-baa8-234a8ed19
@client.1424906162996.3041.DC1.5a5c2a-c382-40b8-baa8-238e6ec9
@client.1424906163996.3043231.DC1.5faa2a-c382-40b8-baa8-23e6ed19
@client.1424906164996.3016731.DC1.5faa5a-c382-40b8-baa8-234ad19

有什么方法可以使用 shell 脚本来执行此操作,该脚本可以读取上述文件并打印出那些以 @client 开头且时间戳早于 1 分钟的字符串。

我有 Ubuntu 12.04 运行.

提取数据的最简单方法是使用 strings 实用程序,告诉它扫描整个文件,例如

strings - inputfile | egrep '@client(\.[[:xdigit:]]+)+(-[[:xdigit:]]+)+'

但如另一个示例中所述,仍然需要考虑时间戳。这可以通过通过 awk 传输原始数据来完成,例如

awk '/@client/ { ts = [=11=]; sub("^.*@client.","",ts); sub("\..*$","",ts); if ( ts >= '$TS' - 60 and ts < '$TS' ) { print [=11=]; } }'

其中 $TS 是您要查找的值(范围比相等更有意义)。

实际上 egrep 是多余的(awk/mawk/gawk 可以执行字符 类,除非您使用 Ubuntu 中的过时版本)。但这有助于将流程分成几个阶段以检查它们是否有效。在 awk 脚本中,

  • 它以一个简单的模式开始 /@client/
  • 我不确定某些字符串会 return 在一行的开头,但是
  • 将行内容$0赋值给一个我可以修改的变量,
  • trim 通过“@client.”关闭部分。
  • trim 去掉以“.”开头的部分(那是毫秒吗?)
  • 将值与 $TS 变量(作为脚本的一部分传入,尽管最近的另一篇文章提醒我们 awk 的“-v”选项也可以)进行比较。
  • 如果比较通过,打印原行

顺便说一句,我知道 awk 有一个“-v”选项,但由于我通常使用最先起作用的最简单工具(例如 sed)来构建脚本,所以我通常会根据习惯直接替换,为作为单独文件传递的脚本保存“-v”。我(很久以前)运行 进入了一个不支持“-v”的 awk——参见 changelog)。但我们可以理所当然地认为它在那里。

您应该尝试使用 strings,它只保留文件中的可打印 ASCII 字符:

strings - 142490.1 |
  awk -F '.' -v timestamp="$(date +%s)" '/^@client/ &&  < (timestamp - 60)*1000 {print}'

这个 awk 脚本可能对这个例子来说太具体了:它查看第一个和第二个点之间的字段,并认为它是时间戳。 如果它小于当前时间戳 - 60 秒,它会打印该行。

希望对您有所帮助。

编辑: 正如 Thomas Dickey 所指出的(我是新来的,我不知道如何真正引用您的帐户),您必须在 strings

上使用 - 标志

编辑2: 经过几次尝试,我们通过改编@ThomasDickey

的另一个答案达到了一个工作版本
FILE=1424911080.1
strings - $FILE |
  awk -v fileTs="${FILE%.*}000" '/@client/ { ts = [=11=] ; sub("^.*@client\.","", ts); sub("\..*$","",ts); if ( ts - fileTs > 500 || ts - fileTs < -500 ) { print [=11=]; } }'

最后,要使时间戳差异 > 500 的行的百分比:

FILE=1424911080.1
tot=$(strings - "$FILE" | grep '@client' |wc -l)
old=$(strings - "$FILE" |
  awk -v fileTs="${FILE%.*}000" '/@client/ { ts = [=12=] ; sub("^.*@client\.","", ts); sub("\..*$","",ts); if ( ts - fileTs > 500 || ts - fileTs < -500 ) { print [=12=]; } }' |
  wc -l)

echo "old : $(( old * 100 / tot ))%"