我正在尝试编写一个简单的.bat脚本,它可以帮助我创建一些我在工作中测试所需的文件。基本上这些文件大约有15,000行,它们都包含一堆十六进制值。我需要的是找到特定值并稍微改变它的文件。我需要它通过向它添加1来找到并更改字节地址0x80020304,然后从该行的末尾减去一个。
例如,它会找到字节地址,以及代码的这个小片段
S325800202E0000000000000000000000000000000000000000000000000000000000000000076 S3258002030000000000D78B21E608000000000202801B020280000802801F4F02800000038044 S32580020320FFFF038000000480FFFF048000000580FFFF0580000006801F4F06800000078015
会变成这个
S325800202E0000000000000000000000000000000000000000000000000000000000000000076 S3258002030000000000D88B21E608000000000202801B020280000802801F4F02800000038043 S32580020320FFFF038000000480FFFF048000000580FFFF0580000006801F4F06800000078015
请记住,在十六进制中,每个字节地址为2个字符。所以你在D7上加1,它就变成了D8,在这行的最后,44减了一个,变成了43。如果最后的数字是40,那就必须变成3F。
我甚至没有任何关于如何做到这一点的线索。我真正知道的是如何设置输入和输出文件,但是当涉及到操作输出文件时,我不是很了解。此外,我不确定它将如何改变,因为我正在使用十六进制。
提前感谢您提供任何帮助。这是非常赞赏。
答案 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 - 谷歌是你的朋友。