【问题标题】:How to read a binary file which has some text string in it in using shell script?如何使用 shell 脚本读取包含一些文本字符串的二进制文件?
【发布时间】:2015-04-28 05:06:53
【问题描述】:

我有一个名为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。

【问题讨论】:

    标签: linux bash file shell binary


    【解决方案1】:

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

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

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

    希望它有所帮助。

    编辑: 正如 Thomas Dickey 所说(我是新来的,我不知道如何真正引用您的帐户),您必须在 strings 上使用 - 标志

    编辑2: 经过几次尝试,我们通过改编@ThomasDickey 的另一个答案达到了一个工作版本

    FILE=1424911080.1
    strings - $FILE |
      awk -v fileTs="${FILE%.*}000" '/@client/ { ts = $0 ; sub("^.*@client\.","", ts); sub("\..*$","",ts); if ( ts - fileTs > 500 || ts - fileTs < -500 ) { print $0; } }'
    

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

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

    【讨论】:

    • 如果不使用“-”选项,字符串会假定它是一个可执行文件,并且会省略部分。
    • @CorentinPeuvrel 我试过这个,但它也打印出了一堆不以@client开头的东西。知道可能出了什么问题吗?
    • 尝试将 awk 脚本替换为 /^@client/ &amp;&amp; $2 &lt; (timestamp - 60)*1000 {print}。我没查到是不是以@client开头的一行
    • @CorentinPeuvrel 为了完整起见,您也可以编辑一下吗?
    • 正如我所说,“字符串”是最简单的方法 - 作为警告,如果字符串不是以空值结尾的,它有时会添加尾随垃圾。
    【解决方案2】:

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

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

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

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

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

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

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

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

    【讨论】:

    • 我尝试了您的建议,但在控制台上没有任何输出。在您的建议中,我该如何检查时间戳?
    • 时间戳检查在脚本的第二块中 -- 我将添加一些文本来帮助。
    • 我将如何传递 $TS 变量值?
    • 还有一件事,看起来我可能偏离了我想要做的事情。我想我需要打印出@client字符串中当前时间戳和时间戳之间的差异大于1分钟的字符串。
    • 在我给出的示例中,$TS 将是一个普通的 shell 变量,例如 TS=1424906161996(awk 用户定义的变量不以“$”开头)。
    猜你喜欢
    • 2023-03-31
    • 1970-01-01
    • 2010-12-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多