CMD forgets file location (The system cannot find the file specified.) - sorting

Started programming a little while ago, and wanted to do a simple program that can sort through images via user input. I wanted to do this via cmd/powershell because I assume it'd be the faster way to do it and it's easier than, say, C or C++ (Please note I'm not the best at this)
I currently have the following:
#ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION
cd "C:\img\Unsorted"
:SORT
FOR /R %%f IN (*.jpg *.png *.gif *.jpeg) DO (
echo Current file is: %%f
start "" "D:\Downloads\ImageGlass_Kobe_8.6.7.13_x64\ImageGlass.exe" %%f
CHOICE /N /C 123 /M "PICK A NUMBER (1 (Folder A), 2 (Folder B), or 3(Delete))"%1
IF ERRORLEVEL ==3 GOTO THREE
IF ERRORLEVEL ==2 GOTO TWO
IF ERRORLEVEL ==1 GOTO ONE
GOTO END
:THREE
echo Current file is: %%f ::This is where the output is: 'Current file is: %f' which clearly indicates it forgot the file
move %%f "C:\img\Delete"
echo To the trash it goes!
taskkill /IM ImageGlass.exe
GOTO END
:TWO
echo Folder B Selected
taskkill /IM ImageGlass.exe
move %%f "C:\img\FolderB"
GOTO END
:ONE
echo Folder A
taskkill /IM ImageGlass.exe
move %%f "C:\img\FolderA"
GOTO END
)
:END
goto SORT
The problem i'm running is that it returns "The system cannot find the file specified." Whenever the move command is sent (because it somehow looses the file info??)

CHOICE /N /C 123Q /M "PICK A NUMBER (1 (Folder A), 2 (Folder B), or 3(Delete))"%1
set "choicemade=option!errorlevel!"
taskkill /IM ImageGlass.exe
if /i "!choicemade!"=="option4" goto :eof
if /i "!choicemade!"=="option3" (
echo Current file is: %%f
move "%%f" "C:\img\Delete"
echo To the trash it goes!
)
(repeat for options 2 & 1)
Notes: Because delayedexpansion has been invoked, the "variable" !errorlevel! is the value of errorlevel as it has changed within the loop, and similarly for choicemade.
Since you want to taskkill regardless of the option taken, include it here - After setting choicemade
I've added option Q for Quit. Since it's the 4th character in the /c string, pressing q will set errorlevel to 4
":eof" (with the colon) is defined by cmd as physical end-of-file
if /i makes the match case-insensitive.
move "%%f" .... because %%f may contain spaces.
The goto end statements can be omitted so that the for loop merely proceeds to the next value.
IMHO, it's not good practice to use cmd's keywords (like sort) as labels or variable-names.
"loose" means "not tight" or "unleash". "lose" means "not win" or "to be deprived of, or cease to have or retain (something)". You need to lose the extra o,

Related

Where is the file of the *beep* noise in batch?

I have a batch file with this line of code in it:
choice /c:123 /n
This is basically a glorified pause that only proceeds if 1, 2, or 3 have been pressed. If I press any other button, It will beep. I've search around the internet for the file location of this beep, but I can't find anything.
Where is the file located? How can I get access this sound file?
Choice.exe imports the Beep function and that is where the sound comes from, it is not a wav file on disk, it is generated dynamically. You can run it in a debugger and set a breakpoint on that function to figure out the exact parameters it is using. On Windows 10 it uses (1500, 500).
You can get the beep sound using a little trick with the FORFILES command as documented on DosTips.com
#echo off
setlocal
::Define a Linefeed variable
set LF=^
::above 2 blank lines are critical - do not remove.
call :hexprint "0x07" rtnvar
FOR /L %%L IN (1,1,5) do echo %rtnvar%
pause
exit /b
:hexPrint string [rtnVar]
for /f eol^=^%LF%%LF%^ delims^= %%A in (
'forfiles /p "%~dp0." /m "%~nx0" /c "cmd /c echo(%~1"'
) do if "%~2" neq "" (set %~2=%%A) else echo(%%A
exit /b

Workaround for failing DEL not setting errorlevel [duplicate]

The batch has to remove files and directories from specific locations and output success or stdout/stderr messages to a new .txt file. I have created the most of the script and it performs exactly as it should, except when the deletion is successful it moves forward to the next line rather than echo a 'successful' message on the log.
echo Basic Deletion Batch Script > results.txt
#echo off
call :filelog >> results.txt 2>&1
notepad results.txt
exit /b
:filelog
call :delete new.txt
call :delete newer.txt
call :delete newest.txt
call :remove c:\NoSuchDirectory
GOTO :EOF
:delete
echo deleting %1
del /f /q c:\Users\newuser\Desktop\%1
if errorlevel 0 echo succesful
GOTO :EOF
:remove
echo deleting directory %1
rmdir /q /s %1
GOTO :EOF
For some reason I can't find the syntax for if del succeeds echo 'successful'. In the above example if I remove the line
if errorlevel 0 echo successful
Everything works fine, but no success message. With this line left in it echoes success for every line.
del and ErrorLevel?
The del command does not set the ErrorLevel as long as the given arguments are valid, it even resets the ErrorLevel to 0 in such cases (at least for Windows 7).
del modifies the ErrorLevel only in case an invalid switch is provided (del /X sets ErrorLevel to 1), no arguments are specified at all (del sets ErrorLevel to 1 too), or an incorrect file path is given (del : sets ErrorLevel to 123), at least for Windows 7.
Possible Work-Around
A possible work-around is to capture the STDERR output of del, because in case of deletion errors, the related messages (Could Not Find [...], Access is denied., The process cannot access the file because it is being used by another process.) are written there. Such might look like:
for /F "tokens=*" %%# in ('del /F /Q "\path\to\the\file_s.txt" 2^>^&1 1^> nul') do (2> nul set =)
To use the code in command prompt directly rather than in a batch file, write %# instead of %%#.
If you do not want to delete read-only files, remove /F from the del command line;
if you do want prompts (in case wildcards ? and/or * are present in the file path), remove /Q.
Explanation of Code
This executes the command line del /F /Q "\path\to\the\file_s.txt". By the part 2>&1 1> nul, the command output at STDOUT will be dismissed, and its STDERR output will be redirected so that for /F receives it.
If the deletion was successful, del does not generate a STDERR output, hence the for /F loop does not iterate, because there is nothing to parse. Notice that ErrorLevel will not be reset in that case, its value remains unchanged.
If for /F recieves any STDERR output from the del command line, the command in the loop body is executed, which is set =; this is an invalid syntax, therefore set sets the ErrorLevel to 1. The 2> nul portion avoids the message The syntax of the command is incorrect. to be displayed.
To set the ErrorLevel explicitly you could also use cmd /C exit /B 1. Perhaps this line is more legible. For sure it is more flexible because you can state any (signed 32-bit) number, including 0 to clear it (omitting the number clears it as well). It might be a bit worse in terms of performance though.
Application Example
The following batch file demonstrates how the above described work-around could be applied:
:DELETE
echo Deleting "%~1"...
rem this line resets ErrorLevel initially:
cmd /C exit /B
rem this line constitutes the work-around:
for /F "tokens=*" %%# in ('del /F /Q "C:\Users\newuser\Desktop\%~1" 2^>^&1 1^> nul') do (2> nul set =)
rem this is the corrected ErrorLevel query:
if not ErrorLevel 1 echo Deleted "%~1" succesfully.
goto :EOF
Presetting ErrorLevel
Besides the above mentioned command cmd /C exit /B, you can also use > nul ver to reset the ErrorLevel. This can be combined with the for /F loop work-around like this:
> nul ver & for /F "tokens=*" %%# in ('del /F /Q "\path\to\the\file_s.txt" 2^>^&1 1^> nul') do (2> nul set =)
Alternative Method Without for /F
Instead of using for /F to capture the STDERR output of del, the find command could also be used like find /V "", which returns an ErrorLevel of 1 if an empty string comes in and 0 otherwise:
del "\path\to\the\file_s.ext" 2>&1 1> nul | find /V "" 1> nul 2>&1
However, this would return an ErrorLevel of 1 in case the deletion has been successful and 0 if not. To reverse that behaviour, an if/else clause could be appended like this:
del "\path\to\the\file_s.ext" 2>&1 1> nul | find /V "" 1> nul 2>&1 & if ErrorLevel 1 (1> nul ver) else (2> nul set =)
Different Approach: Checking File for Existence After del
A completely different approach is to check the file for existence after having tried to delete it (thanks to user Sasha for the hint!), like this, for example:
del /F /Q "\path\to\the\file_s.txt" 1> nul 2>&1
if exist "\path\to\the\file_s.txt" (2> nul set =) else (1> nul ver)
When using this syntax, instead of this
if errorlevel 0 echo successful
you can use this - because errorlevel 0 is always true.
if not errorlevel 1 echo successful
Just use rm from UnxUtils (or gow or cygwin). It sets the errorlevel correctly in case of a nonexistent file, or any errors deleting the file.
This was added as an edit by the original asker, I have converted it to a community wiki answer because it should be an answer, not an edit.
I found out how to do it... one way anyway.
echo Startup > results.txt
#echo off
call :filelog >> results.txt 2>&1
notepad results.txt
exit /b
:filelog
call :delete new.txt
call :delete newer.txt
call :delete newest.txt
call :remove c:\NoSuchDirectory
GOTO :EOF
:delete
echo deleting %1
dir c:\users\newuser\Desktop\%1 >NUL 2>&1
SET existed=%ERRORLEVEL%
del /f /q c:\Users\newuser\Desktop\%1
dir c:\users\newuser\Desktop\%1 2>NUL >NUL
if %existed% == 0 (if %ERRORLEVEL% == 1 echo "successful" )
GOTO :EOF
:remove
echo deleting directory %1
rmdir /q /s %1
GOTO :EOF
IF ERRORLEVEL 0 [cmd] will execute every time because IF ERRORLEVEL # checks to see if the value of ERRORLEVEL is greater than or equal to #. Therefore, every error code will cause execution of [cmd].
A great reference for this is: http://www.robvanderwoude.com/errorlevel.php
>IF /?
Performs conditional processing in batch programs.
IF [NOT] ERRORLEVEL number command
IF [NOT] string1==string2 command
IF [NOT] EXIST filename command
NOT Specifies that Windows should carry out
the command only if the condition is false.
ERRORLEVEL number Specifies a true condition if the last program run
returned an exit code equal to or greater than the number
specified.
I would recommend modifying your code to something like the following:
:delete
echo deleting %1
del /f /q c:\Users\newuser\Desktop\%1
if errorlevel 1 (
rem This block executes if ERRORLEVEL is a non-zero
echo failed
) else (
echo succesful
)
GOTO :EOF
If you need something that processes more than one ERRORLEVEL, you could do something like this:
:delete
echo deleting %1
del /f /q c:\Users\newuser\Desktop\%1
if errorlevel 3 echo Cannot find path& GOTO :delete_errorcheck_done
if errorlevel 2 echo Cannot find file& GOTO :delete_errorcheck_done
if errorlevel 1 echo Unknown error& GOTO :delete_errorcheck_done
echo succesful
:delete_errorcheck_done
GOTO :EOF
OR
:delete
echo deleting %1
del /f /q c:\Users\newuser\Desktop\%1
goto :delete_error%ERRORLEVEL% || goto :delete_errorOTHER
:delete_errorOTHER
echo Unknown error: %ERRORLEVEL%
GOTO :delete_errorcheck_done
:delete_error3
echo Cannot find path
GOTO :delete_errorcheck_done
:delete_error2
echo Cannot find file
GOTO :delete_errorcheck_done
:delete_error0
echo succesful
:delete_errorcheck_done
GOTO :EOF
The answer of aschipfl is great (thanks, helped me a lot!) using the code under Presetting ErrorLevel you get a nice standard function:
Take care to use %~1 instead of %1 in the del statement, or you will get errors if you use a quoted filename.
::######################################################################
::call :DELETE "file.txt"
::call :DELETE "file.txt" "error message"
:DELETE
>nul ver && for /F "tokens=*" %%# in ('del /F /Q "%~1" 2^>^&1 1^> nul') do (2>nul set =) || (
if NOT .%2==. echo %~2
)
goto :EOF
BTW 1: You can give a nifty error message as a second parameter
BTW 2: Using :: instead of REM for comments makes the code even more readable.
Code:
Error Code: (What you did)
if errorlevel 0 echo succesful
The problem here is that you aren't calling errorlevel as a variable and plus you didn't add in the operator to the statement as well.
Correct Code: (Here is what it should actually be.)
if %ERRORLEVEL% EQU 0 echo succesful
Definitions:
EQU: The EQU stands for Equal. This kind of operator is also called a relational operator. Here is the documentation link to operators if you wanna know more, there are other ones but this helped me.
ERRORLEVEL: is declared as a variable and usually get the error level of the last command run usually. Variables are usually called when they are between percent signs like this
%foo%
For some more help on variables, go to cmd (Which you can go to by searching it on windows 10) and type in "set /?", without the quotes. the set command is the command you use to set variables

Windows Command Prompt print text file with delay

I have no experience with command prompt whatsoever, but I'd like to make a batch script (for fun and learn) that would print a text file from a given location, line by line, with a 1 second delay.
I would also want it to be able to pause/unpause when I press a designated key (ex: space) and feed me an extra line (on top of those already programmed to run) when I press another key (ex: enter).
I know I can add a 1 second delay by pinging localhost ping -n 5 127.0.0.1 > nul
And I know I can see the content of a text file using more text.txt, but I don't know how to iterate through an entire text file until EOF is met and I don't know how to pause/resume and feed extra line.
Hope it doesn't sound stupid or out of scope in this context, but it's just something that interests me right know and I know a lot people here have the knowledge to do this.
1) If you have experience in programming, you will know using a for loop is the most common way to do things one by one, e.g. line by line.
2) You can simply use ping localhost -n 2 >nul for 1 second delay, the 2 in the ping is not indicating 2 seconds, but 1 second instead. (I have no idea about that, just get used to it)
3) You can't pause/unpause when cmd is pinging, I mean there's no way to force the program to pause/unpause because the delay process is executed in just a line of code! Or you can magically add some code into it like ping localhost -n 2 pause while(KeyDown(SPACE)) >nul (just kidding :) )
4) Extra lines? Hmm... Remember batch is not a powerful language so... Yeah
Here is a simple code to print text line by line each second in a .txt file
for /f %%a in (your_text.txt) do (
echo %%a
ping localhost -n 2 >nul
)
You could do it synchronously with choice /t 1 (for a 1-second timeout) and some key other than Spacebar. Perhaps P for Pause?
#echo off
setlocal
set "textfile=notes.txt"
echo Hit P to pause / resume, Q to quit.
echo;
for /f "tokens=1* delims=:" %%I in ('findstr /n "^" "%textfile%"') do (
echo(%%J
choice /t 1 /c €pq /d € >NUL
if errorlevel 3 exit /b 0
if errorlevel 2 (
pause >NUL
ping -n 1 -w 750 169.254.1.1 >NUL
)
)
exit /b 0
Unfortunately, choice only allows a-z, A-Z, 0-9, and extended characters 128-254. There's no way to make it listen for Enter or Space. And choice is the only Windows command of which I'm aware that'll accept a single keypress and do something meaningful based on which key was pressed.
I think you'll have to use some sort of compiled language (or possibly PowerShell with a .NET class?) to listen for keypress events on the console. You could probably do it in JavaScript, but you'd have to display your output in a web browser or HTA window.
A "scrolling editor"? It is a crazy idea, isn't it? I LIKE IT! ;-) I adopted your project and add some points...
#echo off
rem ScrollEditor.bat: "dynamic" very simple line editor
rem Antonio Perez Ayala aka Aacini
if "%~1" neq "" if "%~1" neq "/?" goto begin
echo ScrollEditor.bat filename.ext
echo/
echo File lines will be continually scrolling, one per second.
echo/
echo You may pause the scroll via P key. In the "paused" state, the last displayed
echo line is named "current line", and the following commands are active:
echo/
echo #L Return/advance the listing to line #; continue the scroll from there.
echo [#]D Delete [from previous line # up to] current line.
echo I Insert lines after current line; end insert with *two* empty lines.
echo P End "paused" state; continue the scroll from current line on.
echo E End edit and save file, keep original file with .bak extension.
echo Q Quit edit, not save file.
goto :EOF
:begin
if not exist %1 echo File not found & goto :EOF
rem Load file lines into "line" array
set /P "=Loading file... " < NUL
setlocal DisableDelayedExpansion
for /F "tokens=1* delims=:" %%a in ('findstr /N "^" %1') do (
set "line[%%a]=%%b"
set "lastLine=%%a"
)
echo last line: %lastLine%
echo To pause scrolling, press: P
echo/
setlocal EnableDelayedExpansion
set "validCommands=LDIPEQ"
set currentLine=1
:command-P End "paused" state
:ScrollLine
if %currentLine% gtr %lastLine% (
set "currentLine=%lastLine%"
echo EOF
goto GetCommand
)
set "num= %currentLine%"
echo %num:~-4%: !line[%currentLine%]!
set /A currentLine+=1
choice /C PC /N /T 1 /D C >NUL
if errorlevel 2 goto ScrollLine
rem Enter paused state
set /A currentLine-=1
:GetCommand
echo/
set /P "command=Command [#L,#D,I,P,E,Q]? "
set "letter=%command:~-1%"
if "!validCommands:%letter%=!" equ "%validCommands%" goto GetCommand
goto command-%letter%
:command-L Go to line #; continue scrolling
set "currentLine=%command:~0,-1%"
goto ScrollLine
:command-D Delete from line # to current line
set "prevLine=%command:~0,-1%"
if not defined prevLine set "prevLine=%currentLine%"
rem Move lines after last deleted one into deleted lines
set /A currentLine+=1, newCurrent=prevLine-1, lines=currentLine-prevLine
for /L %%j in (%currentLine%,1,%lastLine%) do (
set "line[!prevLine!]=!line[%%j]!"
set /A prevLine+=1
)
set /A currentLine=newCurrent, lastLine=prevLine-1
if %currentLine% equ 0 set "currentLine=1"
echo %lines% line(s) deleted (current=%currentLine%, last=%lastLine%)
goto GetCommand
:command-I Insert lines after current one
echo End insert with *two* empty lines
echo/
rem Read new lines into "ins" array
set "newLine=%currentLine%"
:insertLine
set "line="
set /A newLine+=1
set "num= %newLine%"
set /P "line=+%num:~-3%: "
set "ins[%newLine%]=!line!"
rem The most complex part: end in two empty lines...
if not defined line (
set /A newLine+=1
set "num= !newLine!"
set /P "line=+!num:~-3!: "
if defined line (
set "ins[!newLine!]=!line!"
) else (
set /A newLine-=2
)
)
if defined line goto insertLine
rem Move old lines to new place to make room for new lines
set /A lines=newLine-currentLine, currentLine+=1, newLast=lastLine+lines
for /L %%j in (%lastLine%,-1,%currentLine%) do (
set "line[!newLast!]=!line[%%j]!"
set /A newLast-=1
)
rem Insert new lines in old place
for /L %%j in (%currentLine%,1,%newLine%) do set "line[%%j]=!ins[%%j]!"
set /A lastLine+=lines, currentLine=newLine
echo %lines% line(s) inserted (current=%currentLine%, last=%lastLine%)
goto GetCommand
:command-E End edit, save file
echo Saving file...
move /Y %1 "%~N1.bak"
(for /L %%i in (1,1,%lastLine%) do echo(!line[%%i]!) > %1
:command-Q Quit edit
echo End edit
This program have multiple problems: don't check for valid input in commands, may have problems with special Batch characters and if the first character of a line is a colon, eliminate it. However, it is a good starting point for this project!
Perhaps you may be interested in this similar project.

Batch file for finding top N files which are not of a perticular type

Hi I want some basic help with Windows commands to automate some of my work.
I have a folder in which I get some files, I need to run a fix process in order to correct the file contents.
#echo off
setlocal
set /a "n=0, limit=3"
>"testfile1.txt" (
for /f %%F in ('dir /o-d /b *_SourceFile_*.csv') do (
set %x= echo %%F |findstr /i/v "\.fixed.csv"
if %x% not nul
(
FixFileWithWinFormat.exe %%F
2>nul set /a "n+=1, 1/(limit-n)"||goto :break
)
)
)
:break
echo 'competed'
This bit of code above if I comment out the %x is working the if condition is not making it to work. Don't know why. It could be silly.
set %x= echo %%F |findstr /i/v "\.fixed.csv"
if %x% not nul
These two lines are incorrect. It's better to state what the code is intended to do, otherwise we're guessing.
The set statement can't be used to set an environment variable in that manner - it's very simple, set var=string and %x is an invalid variable to set.
The not nul idea can be accomplished by if not defined x - but no %s.
So - assuming you wish to execute the following parenthesised statement-sequence if the filename in %%f is not found in the file, then
findstr /i "%%f" ".\fixed.csv" >nul
if errorlevel 1 (your statementsequence in parentheses)
should do the task. I'm not sure of the filename fixed.csv here. \.fixed.csv will locate a filename .fixed.csv in the root directory, whereas .\fixed.csv will locate a file fixed.csv in the current directory (and hence the .\ is redundant.)
findstr will find the string contained in %%f in the file, with /i making the seach case-insensitive. >nul redirects any output to nowhere. errorlevel is set to 0 if the text is found, non-zero otherwise.
if errorlevel 1 means "if errorlevel is 1 or greater". Note that if errorlevel 0 means "if errorlevel is 0 or greater" (ie. always, for all intents and purposes) hence to detect errorlevel 0 (ie "text found" you need if not errorlevel 1)
and the opening parenthesis must be on the same physical line as the if
(not sure about your terminating condition; seems to be attempting to force a divide-by-zero after limit iterations. Don't have the time to test atm - soz)

How to replace segment delimiter or unwrap one-liner using Windows command line?

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.
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

Resources