Python實(shí)現(xiàn)Linux命令xxd -i功能
一. Linux xxd -i功能
Linux系統(tǒng)xxd命令使用二進(jìn)制或十六進(jìn)制格式顯示文件內(nèi)容。若未指定outfile參數(shù),則將結(jié)果顯示在終端屏幕上;否則輸出到outfile中。詳細(xì)的用法可參考linux命令xxd。
本文主要關(guān)注xxd命令-i選項(xiàng)。使用該選項(xiàng)可輸出以inputfile為名的C語(yǔ)言數(shù)組定義。例如,執(zhí)行echo 12345 > test和xxd -i test命令后,輸出為:
unsigned char test[] = {
0x31, 0x32, 0x33, 0x34, 0x35, 0x0a
};
unsigned int test_len = 6;
可見,數(shù)組名即輸入文件名(若有后綴名則點(diǎn)號(hào)替換為下劃線)。注意,0x0a表示換行符LF,即'\n'。
二. xxd -i常見用途
當(dāng)設(shè)備沒有文件系統(tǒng)或不支持動(dòng)態(tài)內(nèi)存管理時(shí),有時(shí)會(huì)將二進(jìn)制文件(如引導(dǎo)程序和固件)內(nèi)容存儲(chǔ)在C代碼靜態(tài)數(shù)組內(nèi)。此時(shí),借助xxd命令就可自動(dòng)生成版本數(shù)組。舉例如下:
1) 使用Linux命令xdd將二進(jìn)制文件VdslBooter.bin轉(zhuǎn)換為16進(jìn)制文件DslBooter.txt:
xxd -i < VdslBooter.bin > DslBooter.txt
其中,'-i'選項(xiàng)表示輸出為C包含文件的風(fēng)格(數(shù)組方式)。重定向符號(hào)'<'將VdslBooter.bin文件內(nèi)容重定向到標(biāo)準(zhǔn)輸入,該處理可剔除數(shù)組聲明和長(zhǎng)度變量定義,使輸出僅包含16進(jìn)制數(shù)值。
2) 在C代碼源文件內(nèi)定義相應(yīng)的靜態(tài)數(shù)組:
static const uint8 bootImageArray[] = {
#include " ../../DslBooter.txt"
};
TargetImage bootImage = {
(uint8 *) bootImageArray,
sizeof(bootImageArray) / sizeof(bootImageArray[0])
};
編譯源碼時(shí),DslBooter.txt文件的內(nèi)容會(huì)自動(dòng)展開到上述數(shù)組內(nèi)。通過巧用#include預(yù)處理指令,可免去手工拷貝數(shù)組內(nèi)容的麻煩。
三. 類xxd -i功能的Python實(shí)現(xiàn)
本節(jié)將使用Python2.7語(yǔ)言實(shí)現(xiàn)類似xxd -i的功能。
因?yàn)樽髡咛幱趯W(xué)習(xí)階段,代碼中存在許多寫法不同但功能相同或相近的地方,旨在提供不同的語(yǔ)法參考,敬請(qǐng)諒解。
首先,請(qǐng)看一段短小卻完整的程序(保存為xddi.py):
#!/usr/bin/python
#coding=utf-8
#判斷是否C語(yǔ)言關(guān)鍵字
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新關(guān)鍵字
def IsCKeywords(name):
for x in CKeywords:
if cmp(x, name) == 0:
return True
return False
if __name__ == '__main__':
print IsCKeywords('const')
#Xxdi()
這段代碼判斷給定的字符串是否為C語(yǔ)言關(guān)鍵字。在Windows系統(tǒng)cmd命令提示符下輸入E:\PyTest>python xxdi.py,執(zhí)行結(jié)果為True。
接下來的代碼片段將省略頭部的腳本和編碼聲明,以及尾部的'main'段。
生成C數(shù)組前,應(yīng)確保數(shù)組名合法。C語(yǔ)言標(biāo)識(shí)符只能由字母、數(shù)字和下劃線組成,且不能以數(shù)字開頭。此外,關(guān)鍵字不能用作標(biāo)識(shí)符。所有,需要對(duì)非法字符做處理,其規(guī)則參見代碼注釋:
import re
def GenerateCArrayName(inFile):
#字母數(shù)字下劃線以外的字符均轉(zhuǎn)為下劃線
#'int $=5;'的定義在Gcc 4.1.2可編譯通過,但此處仍視為非法標(biāo)識(shí)符
inFile = re.sub('[^0-9a-zA-Z\_]', '_', inFile) #'_'改為''可剔除非法字符
#數(shù)字開頭加雙下劃線
if inFile[0].isdigit() == True:
inFile = '__' + inFile
#若輸入文件名為C語(yǔ)言關(guān)鍵字,則將其大寫并加下劃線后綴作為數(shù)組名
#不能僅僅大寫或加下劃線前,否則易于用戶自定義名沖突
if IsCKeywords(inFile) is True:
inFile = '%s_' %inFile.upper()
return inFile
以print GenerateCArrayName('1a$if1#1_4.txt')執(zhí)行時(shí),入?yún)⒆址畬⒈晦D(zhuǎn)換為__1a_if1_1_4_txt。類似地,_Bool被轉(zhuǎn)換為_BOOL_。
為了盡可能模擬Linux命令風(fēng)格,還需提供命令行選項(xiàng)和參數(shù)。解析模塊選用optionparser,其用法詳見python命令行解析。類xxd -i功能的命令行實(shí)現(xiàn)如下:
#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(...)原本是以下面的方式調(diào)用:
base = 16; cols = 12; strip = False; inFile = ''; outFile = '' ([base, cols, strip], [inFile, outFile]) = ParseOption(base, cols, strip, inFile, outFile)
其意圖是同時(shí)修改base、cols、strip等參數(shù)值。但這種寫法非常別扭,改用缺省參數(shù)的函數(shù)定義方式,調(diào)用時(shí)只需要寫ParseOption()即可。若讀者知道更好的寫法,望不吝賜教。
以-h選項(xiàng)調(diào)出命令提示,可見非常接近Linux風(fēng)格:
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
基于上述練習(xí),接著完成本文的重頭戲:
def Xxdi():
#解析命令行選項(xiàng)及參數(shù)
([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'模式訪問二進(jìn)制文件
#file = open(inFile, 'rb') #Python2.5以下版本不支持with...as語(yǔ)法
#if True:
#不用for line in file或readline(s),以免遇'0x0a'換行
content = file.read()
#將文件內(nèi)容"打散"為字節(jié)數(shù)組
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
#構(gòu)造數(shù)組定義頭及長(zhǎng)度變量
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會(huì)在每行輸出后自動(dòng)換行
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語(yǔ)法
#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語(yǔ)法,而作者調(diào)試所用的Linux系統(tǒng)僅裝有Python2.4.3。因此,要在Linux系統(tǒng)中運(yùn)行xddi.py,只能寫為file = open(...。但這需要處理文件的關(guān)閉和異常,詳見理解Python中的with…as…語(yǔ)法。注意,Python2.5中使用with...as語(yǔ)法時(shí)需要聲明from __future__ import with_statement。
可通過platform.python_version()獲取Python版本號(hào)。例如:
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
經(jīng)過Windows和Linux系統(tǒng)雙重檢驗(yàn)后,Xddi()工作基本符合預(yù)期。以123456789ABCDEF.txt文件(內(nèi)容為'123456789ABCDEF')為例,測(cè)試結(jié)果如下:
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;
再以稍大的二級(jí)制文件為例,執(zhí)行 python xxdi.py VdslBooter.bin booter.c后,booter.c文件內(nèi)容如下(截取首尾):
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;
綜上可見,作者實(shí)現(xiàn)的xxdi模塊與Linux xxd -i功能非常接近,且各有優(yōu)劣。xxdi優(yōu)點(diǎn)在于對(duì)數(shù)組名合法性校驗(yàn)更充分(關(guān)鍵字檢查),數(shù)組內(nèi)容表現(xiàn)形式更豐富(8進(jìn)制和10進(jìn)制);缺點(diǎn)在于不支持重定向,且數(shù)值寬度不固定(如0xb和0xff)。當(dāng)然,這些缺點(diǎn)并不難消除。例如,用'0x%02x'%val代替hex(val)即可控制輸出位寬。只是,再加完善難免提高代碼復(fù)雜度,也許會(huì)事倍功半。
以上所述是小編給大家介紹的Python實(shí)現(xiàn)Linux命令xxd -i功能,希望對(duì)大家以上幫助!
- Linux上安裝Python的PIL和Pillow庫(kù)處理圖片的實(shí)例教程
- Linux下通過python訪問MySQL、Oracle、SQL Server數(shù)據(jù)庫(kù)的方法
- Linux 發(fā)郵件磁盤空間監(jiān)控(python)
- Python獲取linux主機(jī)ip的簡(jiǎn)單實(shí)現(xiàn)方法
- Linux中Python 環(huán)境軟件包安裝步驟
- Python2.x利用commands模塊執(zhí)行Linux shell命令
- 請(qǐng)不要重復(fù)犯我在學(xué)習(xí)Python和Linux系統(tǒng)上的錯(cuò)誤
相關(guān)文章
pytorch 利用lstm做mnist手寫數(shù)字識(shí)別分類的實(shí)例
今天小編就為大家分享一篇pytorch 利用lstm做mnist手寫數(shù)字識(shí)別分類的實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-01-01
使用TensorFlow實(shí)現(xiàn)二分類的方法示例
這篇文章主要介紹了使用TensorFlow實(shí)現(xiàn)二分類的方法示例,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2019-02-02
Python的ORM框架SQLObject入門實(shí)例
這篇文章主要介紹了Python的ORM框架SQLObject簡(jiǎn)單使用實(shí)例,使用Linux Mint 15、Python 2.7,需要的朋友可以參考下2014-04-04
Pygame實(shí)戰(zhàn)之檢測(cè)按鍵正確的小游戲
這篇文章主要為大家介紹了利用Pygame模塊實(shí)現(xiàn)的檢測(cè)按鍵正確的小游戲:每個(gè)字母有10秒的按鍵時(shí)間,如果按對(duì),則隨機(jī)產(chǎn)生新的字符,一共60s,如果時(shí)間到了,則游戲結(jié)束??靵砀S小編一起學(xué)習(xí)一下吧2021-12-12
python基礎(chǔ)之Numpy庫(kù)中array用法總結(jié)
NumPy(Numerical Python的縮寫)是一個(gè)開源的Python科學(xué)計(jì)算庫(kù),使用NumPy就可以很自然地使用數(shù)組和矩陣,這篇文章主要給大家介紹了關(guān)于python基礎(chǔ)之Numpy庫(kù)中array用法的相關(guān)資料,需要的朋友可以參考下2021-08-08
基于Django?websocket實(shí)現(xiàn)視頻畫面的實(shí)時(shí)傳輸功能(最新推薦)
Django?Channels?是一個(gè)用于在?Django框架中實(shí)現(xiàn)實(shí)時(shí)、異步通信的擴(kuò)展庫(kù),本文給大家介紹基于Django?websocket實(shí)現(xiàn)視頻畫面的實(shí)時(shí)傳輸案例,本案例是基于B/S架構(gòu)的視頻監(jiān)控畫面的實(shí)時(shí)傳輸,使用django作為服務(wù)端的開發(fā)框架,需要的朋友可以參考下2023-06-06
Jupyter Notebook切換conda虛擬環(huán)境的實(shí)現(xiàn)步驟
本文主要介紹了Jupyter Notebook切換conda虛擬環(huán)境的實(shí)現(xiàn)步驟,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-07-07
python采用django框架實(shí)現(xiàn)支付寶即時(shí)到帳接口
這篇文章主要介紹了python采用django框架實(shí)現(xiàn)支付寶即時(shí)到帳接口的相關(guān)資料,需要的朋友可以參考下2016-05-05
將Dataframe數(shù)據(jù)轉(zhuǎn)化為ndarry數(shù)據(jù)的方法
今天小編就為大家分享一篇將Dataframe數(shù)據(jù)轉(zhuǎn)化為ndarry數(shù)據(jù)的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2018-06-06

