Heim >Backend-Entwicklung >Python-Tutorial >Einführung in die Python-Implementierung der Linux-Befehlsfunktion xxd -i
1. Linux-Funktion xxd -i
Der Linux-Systembefehl xxd verwendet das Binär- oder Hexadezimalformat, um den Dateiinhalt anzuzeigen. Wenn der Outfile-Parameter nicht angegeben ist, werden die Ergebnisse auf dem Terminalbildschirm angezeigt; andernfalls werden die Ergebnisse in Outfile ausgegeben. Ausführliche Informationen zur Verwendung finden Sie im Linux-Befehl xxd.
Dieser Artikel konzentriert sich hauptsächlich auf die Option -i des Befehls xxd. Verwenden Sie diese Option, um eine C-Sprach-Array-Definition mit dem Namen „Eingabedatei“ auszugeben. Nach der Ausführung der Befehle echo 12345 > und xxd -i test lautet die Ausgabe beispielsweise:
unsigned char test[] = { 0x31, 0x32, 0x33, 0x34, 0x35, 0x0a }; unsigned int test_len = 6;
Sichtbar, der Array-Name ist der Name der Eingabedatei (falls ein Suffixname vorhanden ist, wird der Punkt durch einen Unterstrich ersetzt). Beachten Sie, dass 0x0a das Zeilenumbruchzeichen LF darstellt, das „n“ ist.
2. Allgemeine Verwendungen von xxd -i
Wenn das Gerät kein Dateisystem hat oder keinen dynamischen Speicher unterstützt Bei der Verwaltung werden manchmal Binärdateien (z. B. Bootloader und Firmware) in statischen C-Code-Arrays gespeichert. Zu diesem Zeitpunkt kann das Versionsarray mithilfe des Befehls xxd automatisch generiert werden. Beispiele sind wie folgt:
1) Verwenden Sie den Linux-Befehl xdd, um die Binärdatei VdslBooter.bin in die Hexadezimaldatei DslBooter.txt zu konvertieren:
xxd -i 31479547a2d967270a9bebad8dc6c6a7 DslBooter.txt
Unter diesen gibt die Option „-i“ an, dass die Ausgabe im C-Include-Dateistil (Array-Modus) erfolgt. Das Umleitungssymbol „94c0ae3fe713a71f7ab631674edbe8bepython xxdi.py an der cmd-Eingabeaufforderung des Windows-Systems ein und das Ausführungsergebnis ist True.
Im folgenden Codeausschnitt werden die Skript- und Codierungsdeklarationen am Kopf und der Abschnitt „Haupt“ am Ende weggelassen.
Bevor Sie ein C-Array generieren, stellen Sie sicher, dass der Array-Name zulässig ist. Bezeichner der C-Sprache können nur aus Buchstaben, Zahlen und Unterstrichen bestehen und dürfen nicht mit einer Zahl beginnen. Darüber hinaus können Schlüsselwörter nicht als Bezeichner verwendet werden. Alle unzulässigen Zeichen müssen verarbeitet werden. Die Regeln finden Sie in den Codekommentaren:
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
zum Drucken von GenerateCArrayName('1a$if1# 1_4.txt') Bei der Ausführung wird die Eingabeparameterzeichenfolge in __1a_if1_1_4_txt konvertiert. Ebenso wird _Bool in _BOOL_ konvertiert.
Um den Linux-Befehlsstil so weit wie möglich zu simulieren, müssen Befehlszeilenoptionen und -parameter bereitgestellt werden. Das Parsing-Modul verwendet optionparser. Einzelheiten zu seiner Verwendung finden Sie unter Python-Befehlszeilen-Parsing. Die Befehlszeilenimplementierung der Funktion xxd -i-like lautet wie folgt:
#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])
Das auskommentierte Def ParseOption(...) wurde ursprünglich aufgerufen auf folgende Weise:
base = 16; cols = 12; strip = False; inFile = ''; outFile = '' ([base, cols, strip], [inFile, outFile]) = ParseOption(base, cols, strip, inFile, outFile)
Die Absicht besteht darin, die Basis-, Spalten-, Streifen- und andere Parameterwerte gleichzeitig zu ändern. Diese Schreibweise ist jedoch sehr umständlich. Verwenden Sie stattdessen die Funktionsdefinitionsmethode mit Standardparametern. Beim Aufruf müssen Sie nur ParseOption () schreiben. Wenn die Leser wissen, wie man es besser schreibt, können Sie mich gerne aufklären.
Verwenden Sie die Option -h, um die Eingabeaufforderung aufzurufen, die dem Linux-Stil sehr nahe kommt:
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
Basierend auf Führen Sie die obigen Übungen durch und vervollständigen Sie dann den Artikel. Highlights:
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)
Versionen unter Python2.5 unterstützen die with...as-Syntax und Linux nicht Auf dem vom Autor zum Debuggen verwendeten System ist nur Python2.4.3 installiert. Um xddi.py in einem Linux-System auszuführen, können Sie daher nur file = open(... schreiben. Dies erfordert jedoch die Behandlung des Schließens und der Ausnahme der Datei. Einzelheiten finden Sie unter Verständnis von with...as... Beachten Sie, dass bei Verwendung der with...as-Syntax in __future__ import with_statement die Python-Versionsnummer beispielsweise über platform.python_version() abgerufen werden kann :
<.>
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 FalseNach zweimaligem Testen auf Windows- und Linux-Systemen funktioniert Xddi() im Wesentlichen wie erwartet '123456789ABCDEF') als Beispiel lauten die Testergebnisse wie folgt:
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;Am Beispiel einer etwas größeren Sekundärdatei nach der Ausführung von python xxdi .py VdslBooter.bin booter.c, der Inhalt der Datei booter.c lautet wie folgt (der Anfang und das Ende werden abgefangen):
Zusammenfassend ist ersichtlich, dass das vom Autor implementierte xxdi-Modul den Funktionen von Linux xxd -i sehr nahe kommt und jedes seine eigenen Vor- und Nachteile hat. Der Vorteil von xxdi besteht darin, dass die Gültigkeit von Array-Namen vollständiger überprüft wird (Schlüsselwortprüfung) und der Ausdruck des Array-Inhalts umfangreicher ist (oktal und dezimal). Der Nachteil besteht darin, dass die Umleitung und die Wertebreite nicht unterstützt werden ist nicht festgelegt (z. B. 0xb und 0xff). Natürlich sind diese Mängel nicht schwer zu beseitigen. Verwenden Sie beispielsweise „0x%02x“%val anstelle von hex(val), um die Ausgabebitbreite zu steuern. Zusätzliche Verbesserungen erhöhen jedoch zwangsläufig die Komplexität des Codes, was dazu führen kann, dass der Aufwand bei halbem Aufwand halbiert wird.
Das Obige ist die Python-Implementierung der vom Herausgeber eingeführten Linux-Befehlsfunktion xxd -i. Ich hoffe, sie wird für alle hilfreich sein!
Weitere Python-Implementierungen zur Einführung der Linux-Befehlsfunktion xxd -i und verwandte Artikel finden Sie auf der chinesischen PHP-Website!