Python实现Linux命令xxd -i功能

发表于 5年以前  | 总阅读数:452 次

一. Linux xxd -i功能

Linux系统xxd命令使用二进制或十六进制格式显示文件内容。若未指定outfile参数,则将结果显示在终端屏幕上;否则输出到outfile中。详细的用法可参考linux命令xxd。

本文主要关注xxd命令-i选项。使用该选项可输出以inputfile为名的C语言数组定义。例如,执行echo 12345 > test和xxd -i test命令后,输出为:


    unsigned char test[] = {
    0x31, 0x32, 0x33, 0x34, 0x35, 0x0a
    };
    unsigned int test_len = 6;

可见,数组名即输入文件名(若有后缀名则点号替换为下划线)。注意,0x0a表示换行符LF,即'\n'。

二. xxd -i常见用途

当设备没有文件系统或不支持动态内存管理时,有时会将二进制文件(如引导程序和固件)内容存储在C代码静态数组内。此时,借助xxd命令就可自动生成版本数组。举例如下:

  1. 使用Linux命令xdd将二进制文件VdslBooter.bin转换为16进制文件DslBooter.txt:

xxd -i < VdslBooter.bin > DslBooter.txt

其中,'-i'选项表示输出为C包含文件的风格(数组方式)。重定向符号'<'将VdslBooter.bin文件内容重定向到标准输入,该处理可剔除数组声明和长度变量定义,使输出仅包含16进制数值。

  1. 在C代码源文件内定义相应的静态数组:

    static const uint8 bootImageArray[] = {
    #include " ../../DslBooter.txt"
    };
    TargetImage bootImage = {
    (uint8 *) bootImageArray,
    sizeof(bootImageArray) / sizeof(bootImageArray[0])
    };

编译源码时,DslBooter.txt文件的内容会自动展开到上述数组内。通过巧用#include预处理指令,可免去手工拷贝数组内容的麻烦。

三. 类xxd -i功能的Python实现

本节将使用Python2.7语言实现类似xxd -i的功能。

因为作者处于学习阶段,代码中存在许多写法不同但功能相同或相近的地方,旨在提供不同的语法参考,敬请谅解。

首先,请看一段短小却完整的程序(保存为xddi.py):


    #!/usr/bin/python
    #coding=utf-8
    #判断是否C语言关键字
    CKeywords = ("auto", "break", "case", "char", "const", "continue", "default",
    "do","double","else","enum","extern","float","for",
    "goto","if","int","long","register","return","short",
    "signed","static","sizeof","struct","switch","typedef","union",
    "unsigned","void","volatile","while", "_Bool") #_Bool为C99新关键字
    def IsCKeywords(name):
    for x in CKeywords:
    if cmp(x, name) == 0:
    return True
    return False
    if __name__ == '__main__':
    print IsCKeywords('const')
    #Xxdi()

这段代码判断给定的字符串是否为C语言关键字。在Windows系统cmd命令提示符下输入E:\PyTest>python xxdi.py,执行结果为True。

接下来的代码片段将省略头部的脚本和编码声明,以及尾部的'main'段。

生成C数组前,应确保数组名合法。C语言标识符只能由字母、数字和下划线组成,且不能以数字开头。此外,关键字不能用作标识符。所有,需要对非法字符做处理,其规则参见代码注释:


    import re
    def GenerateCArrayName(inFile):
    #字母数字下划线以外的字符均转为下划线
    #'int $=5;'的定义在Gcc 4.1.2可编译通过,但此处仍视为非法标识符
    inFile = re.sub('[^0-9a-zA-Z\_]', '_', inFile) #'_'改为''可剔除非法字符
    #数字开头加双下划线
    if inFile[0].isdigit() == True:
    inFile = '__' + inFile
    #若输入文件名为C语言关键字,则将其大写并加下划线后缀作为数组名
    #不能仅仅大写或加下划线前,否则易于用户自定义名冲突
    if IsCKeywords(inFile) is True:
    inFile = '%s_' %inFile.upper()
    return inFile

以print GenerateCArrayName('1a$if1#1_4.txt')执行时,入参字符串将被转换为__1a_if1_1_4_txt。类似地,_Bool被转换为BOOL

为了尽可能模拟Linux命令风格,还需提供命令行选项和参数。解析模块选用optionparser,其用法详见python命令行解析。类xxd -i功能的命令行实现如下:


    #def ParseOption(base, cols, strip, inFile, outFile):
    def ParseOption(base = 16, cols = 12, strip = False, inFile = '', outFile = None):
    from optparse import OptionParser
    custUsage = '\n xxdi(.py) [options] inFile [outFile]'
    parser = OptionParser(usage=custUsage)
    parser.add_option('-b', '--base', dest='base',
    help='represent values according to BASE(default:16)')
    parser.add_option('-c', '--column', dest='col',
    help='COL octets per line(default:12)')
    parser.add_option('-s', '--strip', action='store_true', dest='strip',
    help='only output C array elements')
    (options, args) = parser.parse_args()
    if options.base is not None:
    base = int(options.base)
    if options.col is not None:
    cols = int(options.col)
    if options.strip is not None:
    strip = True
    if len(args) == 0:
    print 'No argument, at least one(inFile)!\nUsage:%s' %custUsage
    if len(args) >= 1:
    inFile = args[0]
    if len(args) >= 2:
    outFile = args[1]
    return ([base, cols, strip], [inFile, outFile])

被注释掉的def ParseOption(...)原本是以下面的方式调用:


    base = 16; cols = 12; strip = False; inFile = ''; outFile = ''
    ([base, cols, strip], [inFile, outFile]) = ParseOption(base,
    cols, strip, inFile, outFile)

其意图是同时修改base、cols、strip等参数值。但这种写法非常别扭,改用缺省参数的函数定义方式,调用时只需要写ParseOption()即可。若读者知道更好的写法,望不吝赐教。

以-h选项调出命令提示,可见非常接近Linux风格:


    E:\PyTest>python xxdi.py -h
    Usage:
    xxdi(.py) [options] inFile [outFile]
    Options:
    -h, --help show this help message and exit
    -b BASE, --base=BASE represent values according to BASE(default:16)
    -c COL, --column=COL COL octets per line(default:12)
    -s, --strip only output C array elements

基于上述练习,接着完成本文的重头戏:


    def Xxdi():
    #解析命令行选项及参数
    ([base, cols, strip], [inFile, outFile]) = ParseOption()
    import os
    if os.path.isfile(inFile) is False:
    print ''''%s' is not a file!''' %inFile
    return
    with open(inFile, 'rb') as file: #必须以'b'模式访问二进制文件
    #file = open(inFile, 'rb') #Python2.5以下版本不支持with...as语法
    #if True:
    #不用for line in file或readline(s),以免遇'0x0a'换行
    content = file.read()

    #将文件内容"打散"为字节数组
    if base is 16: #Hexadecimal
    content = map(lambda x: hex(ord(x)), content)
    elif base is 10: #Decimal
    content = map(lambda x: str(ord(x)), content)
    elif base is 8: #Octal
    content = map(lambda x: oct(ord(x)), content)
    else:
    print '[%s]: Invalid base or radix for C language!' %base
    return
    #构造数组定义头及长度变量
    cArrayName = GenerateCArrayName(inFile)
    if strip is False:
    cArrayHeader = 'unsigned char %s[] = {' %cArrayName
    else:
    cArrayHeader = ''
    cArrayTailer = '};\nunsigned int %s_len = %d;' %(cArrayName, len(content))
    if strip is True: cArrayTailer = ''
    #print会在每行输出后自动换行
    if outFile is None:
    print cArrayHeader
    for i in range(0, len(content), cols):
    line = ', '.join(content[i:i+cols])
    print ' ' + line + ','
    print cArrayTailer
    return
    with open(outFile, 'w') as file:
    #file = open(outFile, 'w') #Python2.5以下版本不支持with...as语法
    #if True:
    file.write(cArrayHeader + '\n')
    for i in range(0, len(content), cols):
    line = reduce(lambda x,y: ', '.join([x,y]), content[i:i+cols])
    file.write(' %s,\n' %line)
    file.flush()
    file.write(cArrayTailer)

Python2.5以下版本不支持with...as语法,而作者调试所用的Linux系统仅装有Python2.4.3。因此,要在Linux系统中运行xddi.py,只能写为file = open(...。但这需要处理文件的关闭和异常,详见理解Python中的with…as…语法。注意,Python2.5中使用with...as语法时需要声明from future import with_statement。

可通过platform.python_version()获取Python版本号。例如:


    import platform
    #判断Python是否为major.minor及以上版本
    def IsForwardPyVersion(major, minor):
    #python_version()返回'major.minor.patchlevel',如'2.7.11'
    ver = platform.python_version().split('.')
    if int(ver[0]) >= major and int(ver[1]) >= minor:
    return True
    return False

经过Windows和Linux系统双重检验后,Xddi()工作基本符合预期。以123456789ABCDEF.txt文件(内容为'123456789ABCDEF')为例,测试结果如下:


    E:\PyTest>python xxdi.py -c 5 -b 2 -s 123456789ABCDEF.txt
    [2]: Invalid base or radix for C language!
    E:\Pytest>python xxdi.py -c 5 -b 10 -s 123456789ABCDEF.txt

    49, 50, 51, 52, 53,
    54, 55, 56, 57, 65,
    66, 67, 68, 69, 70,
    E:\PyTest>python xxdi.py -c 5 -b 10 123456789ABCDEF.txt
    unsigned char __123456789ABCDEF_txt[] = {
    49, 50, 51, 52, 53,
    54, 55, 56, 57, 65,
    66, 67, 68, 69, 70,
    };
    unsigned int __123456789ABCDEF_txt_len = 15;
    E:\PyTest>python xxdi.py -c 5 -b 8 123456789ABCDEF.txt
    unsigned char __123456789ABCDEF_txt[] = {
    061, 062, 063, 064, 065,
    066, 067, 070, 071, 0101,
    0102, 0103, 0104, 0105, 0106,
    };
    unsigned int __123456789ABCDEF_txt_len = 15;
    E:\PyTest>python xxdi.py 123456789ABCDEF.txt
    unsigned char __123456789ABCDEF_txt[] = {
    0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x41, 0x42, 0x43,
    0x44, 0x45, 0x46,
    };
    unsigned int __123456789ABCDEF_txt_len = 15;

再以稍大的二级制文件为例,执行 python xxdi.py VdslBooter.bin booter.c后,booter.c文件内容如下(截取首尾):


    unsigned char VdslBooter_bin[] = {
    0xff, 0x31, 0x0, 0xb, 0xff, 0x3, 0x1f, 0x5a, 0x0, 0x0, 0x0, 0x0,
    //... ... ... ...
    0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
    0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
    };
    unsigned int VdslBooter_bin_len = 53588;

综上可见,作者实现的xxdi模块与Linux xxd -i功能非常接近,且各有优劣。xxdi优点在于对数组名合法性校验更充分(关键字检查),数组内容表现形式更丰富(8进制和10进制);缺点在于不支持重定向,且数值宽度不固定(如0xb和0xff)。当然,这些缺点并不难消除。例如,用'0x%02x'%val代替hex(val)即可控制输出位宽。只是,再加完善难免提高代码复杂度,也许会事倍功半。

以上所述是小编给大家介绍的Python实现Linux命令xxd -i功能,希望对大家以上帮助!

 相关推荐

刘强东夫妇:“移民美国”传言被驳斥

京东创始人刘强东和其妻子章泽天最近成为了互联网舆论关注的焦点。有关他们“移民美国”和在美国购买豪宅的传言在互联网上广泛传播。然而,京东官方通过微博发言人发布的消息澄清了这些传言,称这些言论纯属虚假信息和蓄意捏造。

发布于:1年以前  |  808次阅读  |  详细内容 »

博主曝三大运营商,将集体采购百万台华为Mate60系列

日前,据博主“@超能数码君老周”爆料,国内三大运营商中国移动、中国电信和中国联通预计将集体采购百万台规模的华为Mate60系列手机。

发布于:1年以前  |  770次阅读  |  详细内容 »

ASML CEO警告:出口管制不是可行做法,不要“逼迫中国大陆创新”

据报道,荷兰半导体设备公司ASML正看到美国对华遏制政策的负面影响。阿斯麦(ASML)CEO彼得·温宁克在一档电视节目中分享了他对中国大陆问题以及该公司面临的出口管制和保护主义的看法。彼得曾在多个场合表达了他对出口管制以及中荷经济关系的担忧。

发布于:1年以前  |  756次阅读  |  详细内容 »

抖音中长视频App青桃更名抖音精选,字节再发力对抗B站

今年早些时候,抖音悄然上线了一款名为“青桃”的 App,Slogan 为“看见你的热爱”,根据应用介绍可知,“青桃”是一个属于年轻人的兴趣知识视频平台,由抖音官方出品的中长视频关联版本,整体风格有些类似B站。

发布于:1年以前  |  648次阅读  |  详细内容 »

威马CDO:中国每百户家庭仅17户有车

日前,威马汽车首席数据官梅松林转发了一份“世界各国地区拥车率排行榜”,同时,他发文表示:中国汽车普及率低于非洲国家尼日利亚,每百户家庭仅17户有车。意大利世界排名第一,每十户中九户有车。

发布于:1年以前  |  589次阅读  |  详细内容 »

研究发现维生素 C 等抗氧化剂会刺激癌症生长和转移

近日,一项新的研究发现,维生素 C 和 E 等抗氧化剂会激活一种机制,刺激癌症肿瘤中新血管的生长,帮助它们生长和扩散。

发布于:1年以前  |  449次阅读  |  详细内容 »

苹果据称正引入3D打印技术,用以生产智能手表的钢质底盘

据媒体援引消息人士报道,苹果公司正在测试使用3D打印技术来生产其智能手表的钢质底盘。消息传出后,3D系统一度大涨超10%,不过截至周三收盘,该股涨幅回落至2%以内。

发布于:1年以前  |  446次阅读  |  详细内容 »

千万级抖音网红秀才账号被封禁

9月2日,坐拥千万粉丝的网红主播“秀才”账号被封禁,在社交媒体平台上引发热议。平台相关负责人表示,“秀才”账号违反平台相关规定,已封禁。据知情人士透露,秀才近期被举报存在违法行为,这可能是他被封禁的部分原因。据悉,“秀才”年龄39岁,是安徽省亳州市蒙城县人,抖音网红,粉丝数量超1200万。他曾被称为“中老年...

发布于:1年以前  |  445次阅读  |  详细内容 »

亚马逊股东起诉公司和贝索斯,称其在购买卫星发射服务时忽视了 SpaceX

9月3日消息,亚马逊的一些股东,包括持有该公司股票的一家养老基金,日前对亚马逊、其创始人贝索斯和其董事会提起诉讼,指控他们在为 Project Kuiper 卫星星座项目购买发射服务时“违反了信义义务”。

发布于:1年以前  |  444次阅读  |  详细内容 »

苹果上线AppsbyApple网站,以推广自家应用程序

据消息,为推广自家应用,苹果现推出了一个名为“Apps by Apple”的网站,展示了苹果为旗下产品(如 iPhone、iPad、Apple Watch、Mac 和 Apple TV)开发的各种应用程序。

发布于:1年以前  |  442次阅读  |  详细内容 »

特斯拉美国降价引发投资者不满:“这是短期麻醉剂”

特斯拉本周在美国大幅下调Model S和X售价,引发了该公司一些最坚定支持者的不满。知名特斯拉多头、未来基金(Future Fund)管理合伙人加里·布莱克发帖称,降价是一种“短期麻醉剂”,会让潜在客户等待进一步降价。

发布于:1年以前  |  441次阅读  |  详细内容 »

光刻机巨头阿斯麦:拿到许可,继续对华出口

据外媒9月2日报道,荷兰半导体设备制造商阿斯麦称,尽管荷兰政府颁布的半导体设备出口管制新规9月正式生效,但该公司已获得在2023年底以前向中国运送受限制芯片制造机器的许可。

发布于:1年以前  |  437次阅读  |  详细内容 »

马斯克与库克首次隔空合作:为苹果提供卫星服务

近日,根据美国证券交易委员会的文件显示,苹果卫星服务提供商 Globalstar 近期向马斯克旗下的 SpaceX 支付 6400 万美元(约 4.65 亿元人民币)。用于在 2023-2025 年期间,发射卫星,进一步扩展苹果 iPhone 系列的 SOS 卫星服务。

发布于:1年以前  |  430次阅读  |  详细内容 »

𝕏(推特)调整隐私政策,可拿用户发布的信息训练 AI 模型

据报道,马斯克旗下社交平台𝕏(推特)日前调整了隐私政策,允许 𝕏 使用用户发布的信息来训练其人工智能(AI)模型。新的隐私政策将于 9 月 29 日生效。新政策规定,𝕏可能会使用所收集到的平台信息和公开可用的信息,来帮助训练 𝕏 的机器学习或人工智能模型。

发布于:1年以前  |  428次阅读  |  详细内容 »

荣耀CEO谈华为手机回归:替老同事们高兴,对行业也是好事

9月2日,荣耀CEO赵明在采访中谈及华为手机回归时表示,替老同事们高兴,觉得手机行业,由于华为的回归,让竞争充满了更多的可能性和更多的魅力,对行业来说也是件好事。

发布于:1年以前  |  423次阅读  |  详细内容 »

AI操控无人机能力超越人类冠军

《自然》30日发表的一篇论文报道了一个名为Swift的人工智能(AI)系统,该系统驾驶无人机的能力可在真实世界中一对一冠军赛里战胜人类对手。

发布于:1年以前  |  423次阅读  |  详细内容 »

AI生成的蘑菇科普书存在可致命错误

近日,非营利组织纽约真菌学会(NYMS)发出警告,表示亚马逊为代表的电商平台上,充斥着各种AI生成的蘑菇觅食科普书籍,其中存在诸多错误。

发布于:1年以前  |  420次阅读  |  详细内容 »

社交媒体平台𝕏计划收集用户生物识别数据与工作教育经历

社交媒体平台𝕏(原推特)新隐私政策提到:“在您同意的情况下,我们可能出于安全、安保和身份识别目的收集和使用您的生物识别信息。”

发布于:1年以前  |  411次阅读  |  详细内容 »

国产扫地机器人热销欧洲,国产割草机器人抢占欧洲草坪

2023年德国柏林消费电子展上,各大企业都带来了最新的理念和产品,而高端化、本土化的中国产品正在不断吸引欧洲等国际市场的目光。

发布于:1年以前  |  406次阅读  |  详细内容 »

罗永浩吐槽iPhone15和14不会有区别,除了序列号变了

罗永浩日前在直播中吐槽苹果即将推出的 iPhone 新品,具体内容为:“以我对我‘子公司’的了解,我认为 iPhone 15 跟 iPhone 14 不会有什么区别的,除了序(列)号变了,这个‘不要脸’的东西,这个‘臭厨子’。

发布于:1年以前  |  398次阅读  |  详细内容 »
 相关文章
Android插件化方案 5年以前  |  237228次阅读
vscode超好用的代码书签插件Bookmarks 2年以前  |  8063次阅读
 目录