如何使用Windows命令行替换段分隔符或解包单行?

时间:2014-10-28 08:58:43

标签: windows batch-file findstr

我们的系统将从Linux迁移到Windows机器,因此我准备了一个与我们现有脚本相当的批处理文件。我已经创建了批处理文件,但是在处理下一行代码之前我需要先打开文件。

实施例。这是一个单行,其中分隔符是" {"。 注意:分隔符可以是除元素分隔符之外的任何或可变字符("〜"在这种情况下)。

ISA~00~          ~00~          ~ZZ~SAMSUNGSND     ~14~181087842      ~130214~2300~U~00401~000000003~0~T~>{GS~FA~181087842TEST~SYNNTEST~20130214~2300~810~X~004010{ST~997~131250001{AK1~SC~1809{AK9~A~1~1~1{SE~4~131250001{GE~1~810{IEA~1~000000001

我需要像这样解开它(相当于tr" {"" \ n"< FileName.txt):

ISA~00~          ~00~          ~ZZ~SAMSUNGSND     ~14~181087842      ~130214~2300~U~00401~000000003~0~T~>
GS~FA~181087842TEST~SYNNTEST~20130214~2300~810~X~004010
ST~997~131250001
AK1~SC~1809
AK9~A~1~1~1
SE~4~131250001
GE~1~810
IEA~1~000000001

编辑: 打开后,我需要搜索第三个字段的固定值,如果等于" 1145837"在GS段(第2行)下,将其替换为" 1119283" (相当于sed' / ^ GS / s / 1145837/1119283 /')。

以下是我的批处理文件。我需要在内部插入代码:WriteToLogFile子例程

@echo on

::This ensures the parameters are resolved prior to the internal variable
SetLocal EnableDelayedExpansion

rem Get current date and time as local time.
for /f "delims=" %%a in ('wmic OS Get localdatetime ^| %SystemRoot%\System32\Find.exe "."') do set dt=%%a

rem Reformat the date and time strong to wanted format.
set "YYYY=%dt:~0,4%"
set "MM=%dt:~4,2%"
set "DD=%dt:~6,2%"
set "HH=%dt:~8,2%"
set "Min=%dt:~10,2%"
set "Sec=%dt:~12,2%"
set "TimeStamp=%YYYY%-%MM%-%DD%_%HH%-%Min%-%Sec%"

rem Define name of the list file containing current date and time in name.
set "ListFile=FLIST_%TimeStamp%.lst"

rem Change directory (and drive).
cd /D "C:\VP"

rem Create the list file which is good here as the list of files changes
rem while running this batch file and therefore it is better to work with
rem a list file instead of running a FOR directly for each file in the
rem directory. The list file is not included in this list as it either does
rem not exist at all or it has wrong file extension as only *.txt files are
rem listed by command DIR. The log file EDI.log has also wrong file extension.
dir *.txt /A:-D /B /O:D >"C:\VP\TEST\%ListFile%"

rem It might be useful to delete the log file from a previous run.
if exist EDI.log del EDI.log

rem Process each file in the list file.
cd /D "C:\VP\TEST"
for /F "delims=" %%F in ( %ListFile% ) do call :ProcessFile "%%F"
cd /D "C:\VP"

::rem Delete the list file as not needed anymore. It could be also kept.
::del %ListFile%

rem Exit batch file.
endlocal
goto :EOF


:ProcessFile
rem The parameter passed from first FOR is the file name in double quotes.
set "FileName=%~1"

rem Ignore the files CNtable.txt and Dupfile.txt in same directory.
rem Command goto :EOF just exits here from subroutine ProcessFile.
if "%FileName%"=="CNtable.txt" goto :EOF
if "%FileName%"=="Dupfile.txt" goto :EOF
if "%FileName%"=="VanPointAS2in.bat" goto :EOF
if "%FileName%"=="VP.bat" goto :EOF

rem Get 7th, 9th and 14th element from first line of current file.
cd /D "C:\VP"
for /f "usebackq tokens=7,9,14 delims=~*^" %%a in ( "%FileName%" ) do (
   set "ISAsender=%%a"
   set "ISAreceiver=%%b"
   set "ISActrlnum=%%c"
   goto WriteToLogFile
)

:WriteToLogFile
rem Remove all spaces as ISAsender and ISAreceiver have
rem usually spaces appended at end according to example
rem text. Then write file name and the 3 values to log file.
set "ISAsender=%ISAsender: =%"
set "ISAreceiver=%ISAreceiver: =%"
set "ISActrlnum=%ISActrlnum: =%"
echo %FileName%,%ISAsender%,%ISAreceiver%,%ISActrlnum%>>"C:\VP\TEST\EDI.log"

set "FLAG=N"
if "%ISAsender%"=="APPLESND" (
    if "%ISAreceiver%"=="MANGO" (
        set "FLAG=Y"
        set "VW=AP"
        call :DupCheck
        echo %errorlevel%>>"C:\VP\TEST\EDI.log"
        if errorlevel 1 move /Y "%FileName%" "APPLE"
        echo Moved %FileName% to directory APPLE.
    )
)

if "%ISAsender%"=="APPLESND" (
    if "%ISAreceiver%"=="MANGOES" (
        set "FLAG=Y"
        set "VW=AP"
        call :DupCheck
        echo %errorlevel%>>"C:\VP\TEST\EDI.log"
        if errorlevel 1 move /Y "%FileName%" "APPLE"
        echo Moved %FileName% to directory APPLE.
    )
)

if "%ISAsender%"=="SAMSUNGSND" (
    if "%ISAreceiver%"=="MANGO" (
        set "FLAG=Y"
        set "VW=SS"
        call :DupCheck
        echo %errorlevel%>>"C:\VP\TEST\EDI.log"
        if errorlevel 1 move /Y "%FileName%" "SAMSUNG"
        echo Moved %FileName% to directory SAMSUNG.
    )
)

rem Move to directory BYPASS if all else not satisfied.
if "%FLAG%"=="N" (
    move /Y "%FileName%" "BYPASS"
    echo Moved %FileName% to directory BYPASS
)

rem Exit the subroutine WriteToLogFile.
goto :EOF


:DupCheck
rem Check for ISA control number in file %VW%_table.txt.
%SystemRoot%\System32\Findstr.exe /X /M /C:%ISActrlnum% "C:\VP\TEST\%VW%_table.txt" >nul
if errorlevel 1 goto NewControl

rem This ISA control number is already present in file %VW%_table.txt.
echo Duplicate control %ISActrlnum% found in file %FileName%.
echo %ISActrlnum%,%FileName%>>"C:\VP\TEST\Dupfile.txt"
move /Y "%FileName%" "DUPLICATES"
echo Moved %FileName% to directory DUPLICATES.
rem Exit the subroutine DupCheck.
goto :EOF

:NewControl
echo %ISActrlnum%>>"C:\VP\TEST\%VW%_table.txt"

感谢任何帮助。

1 个答案:

答案 0 :(得分:0)

使用本机批处理命令操作文本文件相当棘手,而且非常慢。大多数任务都可以完成,但需要相当多的高级批处理技术才能使解决方案更加健壮。

您可能对GnuWin32感到非常满意 - 免费收集Windows的unix实用程序。然后,您可以使用熟悉的工具操作文件内容。

另一个不错的选择(我最喜欢的 - 自从我编写它以后就不足为奇了)是使用REPL.BAT - 一个混合JScript /批处理实用程序,它在stdin上执行正则表达式搜索/替换操作并将结果写入stdout。它是纯脚本,可​​以在XP前面的任何Windows机器上本机运行。完整的文档嵌入在脚本中。

我建议您使用\r\n替换您的行分隔符,而不是\n,因为这是换行符的Windows标准。

假设REPL.BAT位于您当前的目录中,或位于PATH中的某个位置,则以下内容将进行所需的更改:

set "file=fileName.txt"
type "fileName.txt" | repl "{" "\r\n" lx >"%file%.new"
move /y "%file%.new" "%file%" >nul

:GS_replace
<"%file%" call repl "^(GS~.*)1145837" "$11119283" >"%file%.new"
set "rtn=%errorlevel%"
move /y "%file%.new" "%file%" >nul
if %rtn% equ 0 goto GS_replace

我担心您的数字字符串可以嵌入更大的数字中,从而导致不必要的替换。您可能希望优化搜索字词以防止此情况发生。

以下只会替换整个字段:

:GS_replace
<"%file%" call repl "^(GS~(?:.*~)*)1145837(~|$)" "$11119283$2" >"%file%.new"
set "rtn=%errorlevel%"
move /y "%file%.new" "%file%" >nul
if %rtn% equ 0 goto GS_replace

以下内容只会替换可能嵌入较大字母数字字符串中的整数:

:GS_replace
<"%file%" call repl "^(GS~(?:.*\D)*)1145837(\D|$)" "$11119283$2" >"%file%.new"
set "rtn=%errorlevel%"
move /y "%file%.new" "%file%" >nul
if %rtn% equ 0 goto GS_replace

在下面的评论中,您说您想要将数字更改限制为GS行的第3个字段。 (这与您在原始问题中所说的完全不同。)这更简单 - 不需要循环:

type "%file%" | repl "^(GS~(.*?~){2})1145837(~|$)" "$11119283$2" >"%file%.new"
move /y "%file%.new" "%file%" >nul