如何编写此脚本来创建差异较小的文件?

时间:2014-04-11 14:33:48

标签: batch-file hex command-prompt

我正在尝试编写一个简单的.bat脚本,它可以帮助我创建一些我在工作中测试所需的文件。基本上这些文件大约有15,000行,它们都包含一堆十六进制值。我需要的是找到特定值并稍微改变它的文件。我需要它通过向它添加1来找到并更改字节地址0x80020304,然后从该行的末尾减去一个。

例如,它会找到字节地址,以及代码的这个小片段

  

S325800202E0000000000000000000000000000000000000000000000000000000000000000076   S3258002030000000000D78B21E608000000000202801B020280000802801F4F02800000038044   S32580020320FFFF038000000480FFFF048000000580FFFF0580000006801F4F06800000078015

会变成这个

  

S325800202E0000000000000000000000000000000000000000000000000000000000000000076   S3258002030000000000D88B21E608000000000202801B020280000802801F4F02800000038043   S32580020320FFFF038000000480FFFF048000000580FFFF0580000006801F4F06800000078015

请记住,在十六进制中,每个字节地址为2个字符。所以你在D7上加1,它就变成了D8,在这行的最后,44减了一个,变成了43。如果最后的数字是40,那就必须变成3F。

我甚至没有任何关于如何做到这一点的线索。我真正知道的是如何设置输入和输出文件,但是当涉及到操作输出文件时,我不是很了解。此外,我不确定它将如何改变,因为我正在使用十六进制。

提前感谢您提供任何帮助。这是非常赞赏。

1 个答案:

答案 0 :(得分:1)

@ECHO OFF
SETLOCAL
set /p "infile=Filename?"
(
FOR /f "usebackqtokens=1*delims=" %%a IN ("%infile%") DO (
  if defined infile (CALL :process %%a
  ) else (echo(%%a)
)
)>newfile.txt

GOTO :EOF

:process
SET line=%1
IF NOT %line:~0,12%==S32580020300 ECHO %line%&GOTO :EOF
set "infile="
:: Increment nybble 21 (count starts at 0)
CALL :inc %line:~21,1%
:: build byte
SET b1=%line:~20,1%%rep%
:: if replacement was 0, then increment was F->0, so incr. prev. nybble
IF %rep%==0 (CALL :inc %line:~20,1%) ELSE (GOTO decb2)
SET b1=%rep%%b1:~-1%
:decb2

:: Repeat above, but decrement on last 2 nybbles.

CALL :dec %line:~-1%
:: build byte
SET b2=%line:~-2,1%%rep%
:: if replacement was F, then decrement was 0->F, so decr. prev. nybble
IF %rep%==F (CALL :dec %line:~-2,1%) ELSE (GOTO rebuild)
SET b2=%rep%%b2:~-1%
:rebuild
SET line=%line:~0,20%%b1%%line:~22,-2%%b2%
ECHO %line%

GOTO :eof

:inc
SET rep=0
FOR %%a IN (F E D C B A 9 8 7 6 5 4 3 2 1 0) DO IF %%a==%1 (GOTO :eof) ELSE (SET rep=%%a)
:dec
SET rep=F
FOR %%a IN (0 1 2 3 4 5 6 7 8 9 A B C D E F) DO IF %%a==%1 (GOTO :eof) ELSE (SET rep=%%a)

我使用了一个名为q23015544.txt的文件,其中包含我的测试数据。 生成newfile.txt

批次中的子字符串是从%var:~m,n%获得的,其中,n是可选的; m是从字符串开始的字符数,如果是负数则从结尾开始。 ,n正=返回的最大长度;负=从结尾的字符中的结束位置; missing =在m

之后全部返回

因此,批处理首先查找目标行 - 它以指示的12个字符的字符串开头。任何其他线,它只是吐出来。对于目标行,它选择最不重要的nybble并调用例程来递增或递减该nybble,并重复该操作,如果这是一个结转(由rep中的替换字符检测到{{} 1}}用于递增或0用于递减)

然后只是重建线并输出它。

结构

F

导致任何数据(commands...)>file 出现在新创建的文件中 - 即使echoed出现在被调用的子例程中。


我已编辑批处理以解决速度问题并允许输入文件名,但我没有测试过这些更改。

您可以使用echo输入文件名或

set /p...

接受文件名作为批处理参数(即批处理文件的参数)

另一个变化是清除' infile'当检测到目标线时。批处理已经知道要读取哪个文件,然后在循环中检测到环境中没有set "infile=%~1" ,因此输出原始行 - 它根本不会调用子程序。这应该会加速它。


流!神奇的词......

infile

此版本应该更快,但它依赖于@ECHO OFF SETLOCAL SET "infile=Filename?" SET "line=" FOR /f "usebackqdelims=" %%a IN ("%infile%") DO CALL :process %%a&IF DEFINED line GOTO nextstep ECHO Target NOT found&GOTO :eof :nextstep sed s/%original%/%line%/g "%infile%" >newfile.txt GOTO :EOF :process SET original=%1 IF NOT %original:~0,12%==S32580020300 GOTO :EOF SET line=%1 :: Increment nybble 21 (count starts at 0) CALL :inc %line:~21,1% :: build byte SET b1=%line:~20,1%%rep% :: if replacement was 0, then increment was F->0, so incr. prev. nybble IF %rep%==0 (CALL :inc %line:~20,1%) ELSE (GOTO decb2) SET b1=%rep%%b1:~-1% :decb2 :: Repeat above, but decrement on last 2 nybbles. CALL :dec %line:~-1% :: build byte SET b2=%line:~-2,1%%rep% :: if replacement was F, then decrement was 0->F, so decr. prev. nybble IF %rep%==F (CALL :dec %line:~-2,1%) ELSE (GOTO rebuild) SET b2=%rep%%b2:~-1% :rebuild SET line=%line:~0,20%%b1%%line:~22,-2%%b2% GOTO :eof :inc SET rep=0 FOR %%a IN (F E D C B A 9 8 7 6 5 4 3 2 1 0) DO IF %%a==%1 (GOTO :eof) ELSE (SET rep=%%a) :dec SET rep=F FOR %%a IN (0 1 2 3 4 5 6 7 8 9 A B C D E F) DO IF %%a==%1 (GOTO :eof) ELSE (SET rep=%%a) 这是第三方产品。我使用GNUSED - 谷歌是你的朋友。