我在Makefile中有这个规则,用 CR LF 替换|||
(三个管道符; hex 7c 7c 7c
) NUL (回车+换行+空;十六进制0d 0a 00
):
rom.hex: rom.txt
hexdump -C rom.txt | cut -c10-60 > rom.hex
sed -i -e 's/ / /g' rom.hex
sed -i -e 's/7c 7c 7c/0d 0a 00/g' rom.hex
这在某些时候有效 - 但是,如果hexdump
的输出将7c 7c 7c
序列分成两行,则它与sed不匹配。
替换必须与匹配的长度相同,以便不移动后续字节。
答案 0 :(得分:3)
在转换为十六进制之前,您可以先进行替换:
rom.hex: rom.txt
sed -e 's/|||/\r\n\x00/g' $< | hexdump -v | cut -c'10-60' >$@
请注意,反斜杠转义符是GNU sed扩展名,因此这不是一个完全可移植的解决方案。如果需要便携式sed命令,则需要将其放在单独的文件中,因为您不能在命令行参数中包含NUL。必须引用字面换行符:
s/|||/^M\
^@/g
为清楚起见,上面的控制字符是
73 2f 7c 7c 7c 2f 0d 5c 0a 00 2f 67 |s/|||/.\../g|
那么规则就是
rom.hex: rom.txt
sed -f "transform.sed" $< | hexdump -v | cut -c'10-60' >$@
答案 1 :(得分:1)
- Toby Speight's helpful answer通过使用 GNU sed
替换源上的数据来优雅地绕过OP的问题,而无需操作在十六进制上。表示(他的便携式替代方法不适用于BSD sed
,但这只是因为替换字符串中的NUL
字符。)
- 这个答案的价值在于完全按照陈述解决OP的问题,特别是使用tr -s '\n' ' '
,并提供相对简单的便携式底部的解决方案 - 从字节表示/文本处理的角度来看,它是有意义的
- 请参阅my other answer,了解使用 hexdump
格式化选项的更简单的解决方案直接生成所需的输出格式 。
功能
注意强>:
sed
来替换值。 hexdump
默认生成的固定宽度多行输出,请将输出通过管道传输到... | fmt -w48
以下命令规范化hexdump -C
输出中的所有空格:
hexdump -vC rom.txt | cut -c10-60 | tr -s '\n' ' ' > rom.hex
请注意添加-v
,可防止信息丢失。
如果没有-v
,相邻重复行中的重复项将表示为*
。
功能
结果是:
由前导和尾随空格预订的单行
字节值全部用单个空格分隔;例如: -
23 21 2f 62 69 6e 2f 62 61 73 68 0a 0a 23 20 23 20 76 3d 24 5f 0a 23 20 23 20 65 63 68 6f 20 22 ...
。
tr
的{{1}}(“挤压”)选项,在执行翻译后{em> -s
到\n
case,ie),将多次出现的目标字符(在本例中为
(空格))折叠成单字符运行。因此:
不再需要用于规范化内部行空间的中间命令(
sed
)。
最终sed -i -e 's/ /...
命令(sed
)可以安全地使用以空格分隔的值作为搜索字符串,而不必担心sed -i -e 's/7c 7c 7c/ ...
'中的换行符的位置输出。
简化有空间:
可以使用单个管道 - 无需以中间形式写入文件,并在以后更新。
hexdump -C
,-i
命令变得可移植(符合POSIX);虽然这种形式可以在Linux和BSD / OSX平台上运行,但它仍然不是严格符合POSIX标准,因为sed
是一个非标准实用程序;请参阅底部,了解严格符合POSIX标准的解决方案。特殊hexdump
变量make
,(第一个)先决条件($<
)和rom.hex
,目标($@
)可以是使用
如果只需要字节值,则不需要rom.txt
-C
选项;这允许简化hexdump
命令,顺便提一下,从输出中删除前导空间(并且还使cut
的{{1}}选项不必要):
tr
-s
:
rom.hex: rom.txt
hexdump -v $< | cut -sd' ' -f2- | tr '\n' ' ' | sed 's/7c 7c 7c/0d 0a 00/g' > $@
表示不会跳过不包含cut -sd' ' -f2-
指定的分隔符(分隔符)的行,这会跳过-s
的尾随空行(除了字节偏移列以外为空)可以输出。-d
使用单个空格作为分隔符将输入拆分为字段。hexdump
输出第二个字段到行尾(-d' '
),有效地剥离第一个字段({{1}中的输入地址偏移列输出)。要使命令完全可移植,可以使用POSIX实用程序-f2-
代替非标准-
实用程序。
此外,额外的hexdump
命令用于从输出中删除前导和尾随空格。
od
hexdump
输出十六进制。 (sed
)字节(rom.hex: rom.txt
od -t x1 -A n -v $< | tr -s '\n' ' ' | sed 's/^ //; s/ $//' | sed 's/7c 7c 7c/0d 0a 00/g' > $@
)跨越多行固定宽度,类似于od -t x1 -A n -v
,除了x
清空输入地址偏移列; 1
确保表示所有字节;没有它,相邻的重复行将表示为hexdump
。-A n
,如上所述,对空白进行规范化,以生成单个长行,其中字节值由单个空格分隔,由单个前导和尾随空格书写。-v
删除了前导和尾随空格。答案 2 :(得分:1)
- 请参阅my other answer了解如何解决问题如上所述或者您是否需要符合 POSIX标准的解决方案。
- 从字节表示格式角度来看,这个答案很有用。
功能
注意强>:
sed
来替换值。 hexdump
默认生成的固定宽度多行输出,请将输出通过管道传输到... | fmt -w48
将格式选项传递给hexdump
,可以绕过问题:
hexdump -ve '1/1 "%02x "'
直接生成所需的输出格式为单个行(将有一个尾随空格)。
-v
阻止重复字节缩写为*
-e '1/1 "%02x "'
:
1/1
指定将以下格式字符串应用于1个字节大小为1的单位,即每个字节。"%02x "
是要应用于每个字节的格式字符串:一个2位十六进制数后跟一个空格。将所有内容放在一起,使用特殊的make
变量$<
,(第一个)先决条件(rom.hex
)和$@
,即目标({{1} }):
rom.txt
替代解决方案使用(非标准)rom.hex: rom.txt
hexdump -ve '1/1 "%02x "' $< | sed 's/7c 7c 7c/0d 0a 00/g' > $@
实用程序;例如xxd
,它可以在Linux和BSD / OSX上使用:
hexdump
rom.hex: rom.txt
xxd -p $< | tr -d '\n' | sed 's/../& /g; s/ $//' | sed 's/7c 7c 7c/0d 0a 00/g' > $@
打印一个字节值的流,不带分隔符,分成固定长度的行。
xxd -p
从输出中删除换行符。
tr -d '\n'
每2个字符后插入一个空格,然后删除该行末尾的尾随空格。
最后,正如Toby Speight在[自清理]评论中指出的那样,您可以使用 GNU 版sed 's/../& /g; s/ $//'
非标准od
选项:
-w
rom.hex: rom.txt
od -t x1 -A n -w1 -v $< | tr -d '\n' | sed 's/7c 7c 7c/0d 0a 00/g' > $@
输出十六进制。 (od -t x1 -A n -w1 -v
)字节(x
)一次1个字节(1
); -w1
省略了输入地址偏移列; -A n
确保表示所有字节;没有它,相邻的重复行将表示为-v
。*
只删除所有换行符,并且由于每行以空格开头,因此结果是一条带有前导空格的长行。