0

our system is going to be migrated from Linux to Windows machine so I'm preparing a batch file equivalent to our existing script. I already have created the batch file but I need to unwrap first the file before processing its next line of codes.

Example. Here is a one-liner wherein the delimiter is "{". Note: Delimiter can be any or variable character except element delimiter ("~" in this case).

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

I need it to be unwrapped like this (equivalent to 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

EDIT: Once unwrapped, I need to search fixed values of third field if equal to "1145837" under GS segment (2nd line) and replace it with "1119283" (which is equivalent to sed '/^GS/ s/1145837/1119283/').

Below is my batch file. I need the code to be inserted somewhere inside :WriteToLogFile subroutine

@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"

Any help is appreciated.

Lordy
  • 81
  • 1
  • 9

1 Answers1

0

Manipulating text files with native batch commands is rather tricky, and quite slow. Most tasks can be done, but it requires quite a few advanced batch techniques to make the solution robust.

You will probably be most happy with GnuWin32 - a free collection of unix utilities for Windows. You could then manipulate file content with familiar tools.

Another good alternative (my favorite - no surprise since I wrote it) is to use REPL.BAT - a hybrid JScript/batch utility that performs a regex search/replace operation on stdin and writes the result to stdout. It is pure script that will run natively on any Windows machine from XP forward. Full documentation is embedded within the script.

I recommend replacing your line delimiter with \r\n rather than \n, as that is the Windows standard for newlines.

Assuming REPL.BAT is in your current directory, or somewhere within your PATH, then the following will make your needed changes:

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

I'm concerned that your string of numeric digits could be embedded within a larger number, leading to an unwanted substitution. You might want to refine your search term to prevent this.

The following would only replace an entire field:

: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

The following would only replace an entire number that may be embedded within a larger alpha-numeric string:

: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

In your comment below, you say you want to restrict the number change to the 3rd field of GS lines. (This is quite different than what you stated in your original question.) This is much simpler - no loop is required:

type "%file%" | repl "^(GS~(.*?~){2})1145837(~|$)" "$11119283$2" >"%file%.new"
move /y "%file%.new" "%file%" >nul
Community
  • 1
  • 1
dbenham
  • 127,446
  • 28
  • 251
  • 390
  • thanks for your reply, how do I make the delimiter inside repl variable as file may contain other segment delimiter such as asterisk or any char? For the GS part, if third field equals 1145837 just replace it by 1119283 which is false for this case since the field is SYNNTEST. Here I need to search the full file having multiple GS segments and replace the third field if equal to 1145837 – Lordy Oct 28 '14 at 15:31
  • Umm... use a variable `"%var%"` or argument `"%~1"` as the search string instead of the constant `"{"`. I should have thought that was fairly obvious. What 3rd field are you talking about? - your question never talks about replacing a string in a specific field. In fact, I don't see how your posted batch script relates at all to the problem as you describe it. Your unix code examples are reading from a file, but nowhere does :WriteToLogFile read from a file. – dbenham Oct 28 '14 at 15:55
  • EDIT - Simplified the loop that modifies `GS~` lines by using the new return code features of REPL.BAT version 5.0 – dbenham Oct 28 '14 at 21:51
  • 1
    EDIT - Appended a solution showing how to selectively modify the 3rd field only of GS records. – dbenham Oct 28 '14 at 21:59
  • Sorry for the confusion I have updated my question. Your last set of codes did the job. It's good you have created REPL.bat works like a charm. Is this correct for the segment delimiter part, SET "var=%~1", then repl "%var%" "\r\n" lx >"%file%.new" to replace variable values of segment delimiter? – Lordy Oct 29 '14 at 02:48
  • @Lordy - That should work, provided you provide the delimiter as an argument when you call the script. But you don't need the VAR variable. You could simply use `repl "%~1" "\r\n" lx >"%file%.new"` – dbenham Oct 29 '14 at 04:10
  • Tried to run this inside REPL.bat directory but did not replaced the segment delimiter. C:\VP>type FileName_3.txt | repl "%~1" "\r\n" lx . Am I missing something? – Lordy Oct 29 '14 at 05:37
  • Is that command in a script? Did you supply a delimiter value argument for `%1` when you called the script? If you cannot figure this out, then ask a new question, showing your script, how you call it, and the result. But this is really basic batch functionality. Google "Windows batch arguments" – dbenham Oct 29 '14 at 11:44
  • I forgot to supply the argument, geez. Thanks again. – Lordy Oct 30 '14 at 08:10