Find multiple values in different lines using command-line | CMD - command-line

I have multiple results (Radiology, Labs, Pathology, Transcriptions) for the same patient in a file and I am only interested in getting results for a set of particular values. For example: I want to look for a radiology report on the first line and patient MRN 123456789 on the second line.
Can this be achieved using findstr? Thanks
MSH|^~\&|RADIOLOGY|1|SCM||20150303||ORU|20150303|T|2.3|20150303
PID||1111111|123456789^^^MRN_SB^||TEST^PATIENT^^^||19000101||^^||
PV1|1|E|ER^ER^1^SB||||||||||||||||||||||||||||||||||||||||||||||
ORC|RE|36543654|36543654|3003487889

#ECHO OFF
SETLOCAL
:: remove variables starting $
FOR /F "delims==" %%a In ('set $ 2^>Nul') DO SET "%%a="
SET "found="
SET "mrn=%1"
FOR /f "delims=" %%o IN (q29931949.txt) DO (
FOR /f "tokens=1-4delims=|" %%a IN ("%%o") DO (
IF DEFINED found IF "%%a"=="PID" (
SET "$2=%%o"
CALL :report "%%b" "%%c" "%%d"
)
SET "found="
IF "%%a"=="MSH" IF "%%b"=="RADIOLOGY" SET found=Y
IF "%%a"=="MSH" IF "%%c"=="RADIOLOGY" SET found=Y
IF DEFINED found SET "$1=%%o"
)
)
GOTO :EOF
:report
SET "field=%~1"
IF NOT DEFINED field GOTO :EOF
FOR /f "tokens=1delims=^^" %%r IN ("%~1") DO SET "field=%%r"
IF "%field%"=="%mrn%" FOR /F "tokens=1*delims==" %%r In ('set $') DO ECHO(%%s
shift
GOTO report
I used a file named q29931949.txt containing your data for my testing.
You don't really supply enough information to produce a result. For instance, is "MRN" a required data item?
This procedure will find two consecutive lines, the first one having "MSH" in he first column and "RADIOLOGY" in the second or third and the second line having "PID" in the first column snd either the second, third or fourth column containing the target number.
You'd run the routine using thisbatchaname 123456789
It accepts the parameter 123456789 and assigns that to mrn.
It then reads the file and assigns each line in tun to %%o, and tokenises the line on |, applying tokens 1-4 to %%a..%%d rspectively.
The main loop sets found to empty and then to Y only if the first field is MSH and the second or thid RADIOLOGY. If the found flag is set, the original line in %%o is applied to $1. Only if found is set at the start of the loop (which means that the previous line is MSH/RADIOLOGY) will the routine :report be called after $2 has the original contents of the second line assigned.
The :report routine sets field to the first parameter to see whether there are remaining parameters to process. The for then assigns the part of the field up to the first caret (^) to field. If this matches the mrn input from the command line, then the $ variables are echoed to the console (you don't say what you actually want to do with the data). Regardless, the remaining parameters are checked.
The reson for checking the second/third(/fourth) parameter is to cater for the presence or absence of data in the fields as consecutive | characters are interpreted as a single delimiter.

Find a HL7 parser library for Your programming/scripting language of choice and use it. It is not worth it to write a HL7 parser from scratch. There should be libraries available for all popular languages that You can use.
If You then have specific questions, feel free to ask again.

Related

How to make this powershell command work inside a loop in batch?

Trying to find the difference. But when this powershell command is inside in the findstr, it fails. On its own, it returns the correct value. Also, without the loop, it returns the correct value.
echo:!newvalue!| findstr /R "^[0123456789][0123456789]\.[0123456789]$" >nul
if errorlevel 1 (
set newvalue=
) else (
FOR /F "usebackq delims=" %%i IN (`powershell -nop -c "'{0:n1}' -f (%newvalue% - 12.0)"`) DO (SET difference=%%i)
echo %difference%
)
Can anyone figure out what I'm missing/did wrong?
Thanks in advance.
I recommend reading How does the Windows Command Interpreter (CMD.EXE) parse scripts?
Windows command processor replaces all environment variable references using syntax %variable% inside a command block starting with ( and ending with matching ) already on parsing the command line using this command block. This means the command line echo %difference% inside ELSE branch command block of the IF command is modified by cmd.exe before command IF is executed at all. %difference% is replaced by current value of environment variable difference or an empty string in case of environment variable difference is not defined somewhere above the IF condition. In latter case echo  is the command line remaining after parsing the command block and therefore shows status of command echoing instead of the string value assigned to environment variable difference in the command line above. The solution with already enabled delayed environment variable expansion is using echo !difference! in ELSE command block.
A solution for this floating point subtraction without usage of PowerShell can be seen below:
#echo off
setlocal EnableExtensions EnableDelayedExpansion
if defined NewValue goto Validate
:UserPrompt
set /P "NewValue=Enter value between 00.0 and 99.9: "
:Validate
echo:!NewValue!| %SystemRoot%\System32\findstr.exe /R "^[0123456789][0123456789]\.[0123456789]$" >nul
if errorlevel 1 set "NewValue=" & goto UserPrompt
for /F "tokens=1,2 delims=." %%I in ("%NewValue%") do set "PreComma=%%I" & set "PostComma=%%J"
set /A Difference=1%PreComma% - 112
set "Difference=%Difference%.%PostComma%"
echo Difference is: %Difference%
endlocal
After validating that the string assigned to environment variable NewValue indeed consists of two digits, a point and one more digit as requested and expected and described at How can I do a negative regex match in batch?, the floating point number string is split up on . into pre-comma and post-comma number strings.
The pre-comma number is subtracted by 12 using an arithmetic expression. But it must be taken into account that an integer number with a leading 0 is interpreted by cmd.exe on evaluation of the arithmetic expression as octal number. That is no problem for 00 to 07. But 08 and 09 would be invalid octal numbers and so Windows command processor would use value 0 resulting in a wrong subtraction result if simply set /A Difference=PreComma - 12 would have been used in batch file. The workaround is concatenating the string 1 with the pre-comma string to a number string in range 100 to 199 and subtract 112 to get the correct result.
The post-comma value does not need to be modified and so the Difference value is determined finally with concatenating the result of the arithmetic expression with the unmodified post-comma number string.
It is possible to get the Difference value also always with two digits by inserting following additional command lines above echo Difference is: %Difference%:
if %Difference:~0,1% == - (
if %Difference:~2,1% == . set "Difference=-0%Difference:~1%"
) else (
if %Difference:~1,1% == . set "Difference=0%Difference%"
)
This solution avoids also the problem that floating point result of PowerShell is formatted according to region and language settings. For example in Germany and Austria the decimal symbol is , and not . which means the subtraction result output by PowerShell for 15.3 - 12.0 is 3,3 and not 3.3.
For understanding the used commands and how they work, open a command prompt window, execute there the following commands, and read entirely all help pages displayed for each command very carefully.
echo /?
endlocal /?
findstr /?
for /?
goto /?
if /?
set /?
setlocal /?
See also single line with multiple commands using Windows batch file.
This is not technically an answer, as you've already received and accepted one a perfectly good one.
It is just to allow you to visualise a method of taking the string from your file, splitting it at the decimal point and subtracting 12, from a whole number greater or equal to 12, (see the accepted answer for whole numbers less than 12), all without 'loops' or PowerShell
#Echo Off
Rem Create a variable from the first line of your file
Set /P "newvalue="<"file.tmp"
Echo [%newvalue%]
Rem Exit if the string 'value' does not exist in '%newvalue%'
If "%newvalue%"=="%newvalue:*value=%" Exit /B
Rem ReSet the variable to everything after the string 'value'
Set "newvalue=%newvalue:*value=%"
Echo [%newvalue%]
Rem ReSet the variable to everything up to the first 'space' character
Set "newvalue=%newvalue: ="&:"%"
Echo [%newvalue%]
Rem ReSet the variable, removing the unneeded leading '=' character
Set "newvalue=%newvalue:~1%"
Echo [%newvalue%]
Rem Set a new variable to the whole number, i.e. everything up to the first '.' character
Set "whole=%newvalue:.="&:"%"
Echo [%whole%]
Rem Set a new variable to the decimal, i.e. everything after the '.' character
Set "decimal=%newvalue:*.=%"
Echo [%decimal%]
Rem Subtract 12 from the whole number
Set /A remainder=100+whole-112
Echo [%remainder%]
Rem ReJoin the variables to show the difference
Echo [%remainder%.%decimal%]
Pause
Obviously in your script proper, you'd only need:
#Echo Off
Set /P "newvalue="<"file.tmp"
If "%newvalue%"=="%newvalue:*value=%" Exit /B
Set "newvalue=%newvalue:*value=%"
Set "newvalue=%newvalue: ="&:"%"
Set "newvalue=%newvalue:~1%"
Set "whole=%newvalue:.="&:"%"
Set "decimal=%newvalue:*.=%"
Set /A remainder=100+whole-112
Echo %remainder%.%decimal%
Pause

How to do a postgres Select statement which contains round brackets in a batch?

I am trying to do a select in to a postgres DB via batch file.
The postgres DB offers a command line interface (psql) where you can pipe in DB commands which is here done in for loop. Look at how pg_cmd is stiched together. The select pd_SelCmd is echoed to pg_SelCall.
In the for statement the command is executed but since the select contains round brackets, they cause a miss interpretation and an error:
"FROM" cant be processed syntactically at this point.
How can the round brackets be kind of escaped to get the request to work?
The expected response from DB looks like:
max
-------------------------
2016-12-29 09:40:09.842
(1 Line)
The batch used so far was this
setlocal enabledelayedexpansion
Set "PgRootPath=C:\Program Files\PostgreSql\9.5.5-1\bin"
Call :GetDoneTime 56665454 DONE_TIME
echo = DONE_TIME=!DONE_TIME!
Goto :EOF
:GetDoneTime
set "ERRORLEVEL="
set "MC_UID=%~1"
set "ReturnDoneTimeValueRef=%~2"
set "DataVal=NULL"
set "PGPASSWORD=frontenduser"
set "PGCLIENTENCODING=utf-8"
set pd_SelCmd=SELECT max(t.endDate) FROM Ticket t JOIN Device d on t.device_id = d.id WHERE t.state in ('APPROVED','IN_PROGRESS', 'IN_ACTIVITY') AND d.uid='!MC_UID!';
set pg_SelCall="!PgRootPath!\psql" -U frontenduser -h localhost -d ppsdb
REM if call to psql produces an fatal error, the error number will be passed to for loop on third parameter in third line
set pg_cmd="echo !pd_SelCmd! | !pg_SelCall! || echo/ & echo/ & call echo NULL NULL %%^^^errorlevel%%"
set "pg_cmd=!pg_cmd:)=^)!"
REM Execute PG command. Resulting DataValue obtained from third row
REM Check for errors of call
for /f "skip=2 tokens=1,2,3" %%i in ('!pg_cmd!') do (
REM Get value in first and second parameter from split - which is from third row
set "DataVal=%%i %%j"
REM If error happend, report it. Error code is obtained in 3rd parameter.
if "!DataVal!"=="NULL NULL" (
echo ## Postgres DB operation failed with ERROR: %%~k
set "DataVal=NULL"
) else (
REM Check if result is not valid
if "!DataVal:~0,1!"=="(" set "DataVal=NULL"
)
goto GotDoneTime
)
:GotDoneTime
if not '!ReturnDoneTimeValueRef!'=='' set "!ReturnDoneTimeValueRef!=!DataVal!"
if "!DataVal!"=="NULL" exit /b 1
exit /b 0
Just a few errors here. Unfortunately, I don't know postgresql, nor do I have the requisite database, so I can't test it, but here goes...
First, labels are not allowed in a code-block (parenthesised series of statements) and :: is a broken label. Within a code block, rem should be used for remarks.
Next, replacing your '!pg_cmd! in the for loop with type q41353737.txt (where q41353737.txt is a file containing the expected data output from the command you posted) then dataval is set to 09:40:09.842 BUT since there is a fourth line in the file, the next line will also be processed and dataval will be set to Line).
To overcome this, you could simply change this to
rem If error happened, report it. Error code is obtained in 3rd parameter.
if not '%%~k'=='' echo ## Postgres DB operation failed with ERROR: %%~k
rem If operation succeeded, get value in second parameter from split - which is from second data column
if '%%~k'=='' SET DataVal=%%~j
goto done
)
:done
so that only the third line is processed and then the for loop is unceremoniously terminated.
Next problem is the problem of which you complain. The ) is terminating the for ... (, so you need to tell cmd that that particular ) is part of the command to be executed, not of the for, so you need to escape it with a caret (( becomes ^))
The easiest way is probably, just before the for to add a line
set "pg_cmd=!pg_cmd:)=^)!"
which should appropriately prefix all ) in the command withh the requisite caret.
I suspect you'll also have trouble with the other problem characters so a similar process applied to | will probably be required, ie.
set "pg_cmd=!pg_cmd:|=^|!"
Which is where I have to leave it, since I've no way of correctly executing the command itself.

CMD - If exists <file>

The below commands (with debug lines added - indented) should only redirect the echo's output to a file, should it already exist, according to my understanding.
However, it would seem that if exist %test0% always fills the file (creating it if non-existant) with the echo's output.
Does anyone know what is wrong?
#echo off
type test.bat
set test0="e:\documents and settings\administrator\desktop\test.log"
echo.&echo.
if exist %test0% (echo !!Exists!!) else (echo !!Doesn't Exist!!)
(if exist %test0% echo.&echo.&echo -------------------------------------------------&echo.&echo.)>>%test0%
And the file gets created(!)
EDIT: This above was a simplified example, and unfortunately MSalters answer doesn't help me solve the full command (I had hoped it would). The full one line if statement is:
if exist %test0% (echo.&echo.&echo -------------------------------------------------&echo.&echo.) else (set /p .=<nul)>>%test0%&set errorlevel=0||set errorlevel=1
How would I have whichever condition of the if matched output to the file (Hopefully with only one reference to the file, i.e., not one in each if conditional), and have the errorlevel set based on the existance of the file?
Could anyone help with the actual full command issue?
You should never set ERRORLEVEL directly. That name is reserved for reporting on the results of the prior command. When you set the value directly, you override the intended functionality and it ceases to expand to the actual ERRORLEVEL, it expands to the value you set instead. That can break all kinds of code.
You can force the ERRORLEVEL to a value by running a command with known result, redirecting output to nul if necessary: ver >nul sets ERRORLEVEL to 0, set /p .=<nul sets ERRORLEVEL to 1.
You can force the ERRORLEVEL to any particular value of your choosing by using cmd /c exit /b N, where N is an integral value.
You also have faulty logic. Your IF command succeeds (has no error) regardless whether the condition evaluates to TRUE or FALSE. If you want to set the ERRORLEVEL, then you need to do it within your parenthesized blocks.
There is nothing wrong with putting everything on one line, but I find the code easier to read when using multiple lines for complex statements like yours. I believe the following is what you are looking for.
if exist %test0% (
echo.
echo.
echo -------------------------------------------------
echo.
echo.
ver >nul
) >>%test0% else (
set /p .=<nul
)
Edit in response to comments
Not much change needed.
if exist %test0% (
(
echo.
echo.
echo -------------------------------------------------
echo.
echo.
set ERR=0
) >>%test0%
) else (
copy nul %test0%
set ERR=1
)
Check your parentheses. (x) >> output.log redirects the output of x to output.log. That means the redirection happens regardless of what the output is, and in particular always creates the file.
Now if you'd write if Y (echo Text >> output.log) the redirection would be conditional on Y, and might not happen.
[edit]
With the question as it's worded now, the simple solution seems to be:
Set %ERRORLEVEL% based on exist %test0%. No redirection has happened at this point.
Use %ERRORLEVEL% to determine what to do. You can change %test0% without altering %ERRORLEVEL%.
BTW, ERRORLEVEL is not %ERRORLEVEL%

Parsing first row of csv into sql table using batch file

I have some csv files, I need to open csv file, read first line of csv and convert it into temporary sql table, and then load data into the sql table as follows:
Read the lines of the CSV and for each line:
Break it into fields create one temporary sql table
Insert those fields into a row of the database table
I tried something like this
This script is now divided in 4 parts,file initialization; file creation, process and copy data,
everything is working fine except,on fil.sql I am getting output as
CREATE TEMP TABLE temtab(
firstcolumn character varying (255),
secondcolumn character varying (255),
lastcolumn character varying (255),
);
\COPY temtab from bio.csv WITH DELIMITER ; csv HEADER
While I want without comma for last col
CREATE TEMP TABLE temtab (
firstcolumn character varying (255),
secondcolumn character varying (255),
lastcolumn character varying (255)
);
\COPY temtab from bio.csv WITH DELIMITER ; csv HEADER
#echo off
::setlocal enabledelayedexpansion
REM Assiging dir to current directory
SET dir=%CD%
REM Defining database name
SET dbname=****
REM Defining Host name
SET host=****
REM Defining user
SET user=****
REM Defining Port
SET port=****
REM SQL file where query is to be executed
SET sqfile=fil.sql
SET fi=bio.csv
call:fileinitialization
call:filecreation
call:proces
call:copydata
goto:eof
:fileinitialization
REM Assigning name of temporary table
SET tabnam=temtab
REM Setting delimiter to variable delim
SET delim=;
REM Declaring variable numfields to store index of variable names array
set numFields=0
echo para setted
set fi=bio.csv
SET tex=text
SET com=,
GOTO:EOF
:filecreation
REM Setting create temporary table command with table name tabnam
SET creat=CREATE TEMP TABLE %tabnam%
echo %creat%
GOTO:EOF
:proces
REM Executing loop for each file in current directory
echo %creat%>fil.sql
REM Read the lines of the CSV file
For /F "eol==" %%A in (bio.csv) Do ( set "line=%%A"
REM check if index of array is 0
if !numFields! equ 0 (
REM Fisrt line, Store in array name
for %%B in (!line: ^=!) do (
echo %%B character varying (255^),>>fil.sql
set /A numFields+=1
set name[!numFields!]=%%B
) ) )
GOTO:EOF
:copydata
echo \COPY %tabnam% from %fi% WITH DELIMITER %delim% csv HEADER
echo \COPY %tabnam% from %fi% WITH DELIMITER %delim% csv HEADER;>>fil.sql
GOTO:EOF
::endlocal
Pause
Although I don't know the format of SQL tables, I can show you how to read a CSV file. The Batch file below read all lines from the file; it first take field names from first line (CSV header) and create an array of variable names (eliminating possible spaces in field names); then it read the rest of lines and assign each field value to its corresponding Batch variable.
ProcessCSV.BAT:
#echo off
rem General-purpose CSV file reader program
rem Antonio Perez Ayala
setlocal EnableDelayedExpansion
set numFields=0
rem Read the lines of the CSV file
for /F "delims=" %%a in (CSVfile.csv) do (
set "line=%%a"
if !numFields! equ 0 (
rem It is the first line: break it into an array of field names (removing spaces)
for %%b in (!line: ^=!) do (
set /A numFields+=1
set name[!numFields!]=%%b
)
) else (
rem Replace spaces by Ascii-128 (to avoid split values that may have spaces)
set "line=!line: =Ç!"
rem Insert any char. at beginning of each field, and separate fields with spaces
set i=0
for %%b in (X!line:^,^= X!) do (
set "field=%%b"
rem Recover spaces in this field, if any
set "field=!field:Ç= !"
rem And assign it to corresponding variable (removing first character)
set /A i+=1
for %%i in (!i!) do set "!name[%%i]!=!field:~1!"
)
rem At this point all variables have the values of current record.
rem They may be accessed explicitly (ie, from example CSVfile.csv):
echo/
echo Record of !FirstName! !LastName!
rem ... or implicilty via the NAME array:
for /L %%i in (3,1,!numFields!) do (
for %%b in (!name[%%i]!) do echo %%b: !%%b!
)
)
)
CSVfile.csv:
First Name,Last Name,Address,Postal Code,Company,Departament,Floor,Phone,Mobile
John,Smith,123 Fake Street,45612,SomeCo,Accounting,4,123-555-5555,123-555-5556
Jane,Doe,123 Fake Street,,SomeCo,,4,123-555-5555,123-555-5556
output:
Record of John Smith
Address: 123 Fake Street
PostalCode: 45612
Company: SomeCo
Departament: Accounting
Floor: 4
Phone: 123-555-5555
Mobile: 123-555-5556
Record of Jane Doe
Address: 123 Fake Street
PostalCode:
Company: SomeCo
Departament:
Floor: 4
Phone: 123-555-5555
Mobile: 123-555-5556
Please be aware that this program use several advanced Batch techniques. I suggest you to get help on every command you don't completely understand (ie: SET /?) and read it carefully. If after this process you have further questions about this program, just post they as an edit in your original question.
The most complex part of this program is responsible to assign empty strings to variables when the corresponding field is empty (two commas side by side); if the file have not empty fields, the program may be somewhat simpler. Also, this program (as most Batch solutions) may give erroneous results if certain special Batch characters appear in the file, like !. Most of these characters may be managed if required via certain modifications in the program.
EDIT: Modified version when no empty fields exists
#echo off
rem CSV file reader program when no empty fields exist
rem Antonio Perez Ayala
setlocal EnableDelayedExpansion
set numFields=0
rem Read the lines of the CSV file
for /F "delims=" %%a in (CSVfile.csv) do (
set "line=%%a"
if !numFields! equ 0 (
rem It is the first line: break it into an array of field names (removing spaces)
for %%b in (!line: ^=!) do (
set /A numFields+=1
set name[!numFields!]=%%b
)
) else (
rem Replace spaces by Ascii-128 (to avoid split values that may have spaces)
set "line=!line: =Ç!"
rem Separate fields (using comma as standard Batch separator)
set i=0
for %%b in (!line!) do (
set "field=%%b"
rem Assign this field to corresponding variable, recovering spaces
set /A i+=1
for %%i in (!i!) do set "!name[%%i]!=!field:Ç= !"
)
rem At this point all variables have the values of current record.
rem They may be accessed explicitly (ie, from example CSVfile.csv):
echo/
echo Record of !FirstName! !LastName!
rem ... or implicilty via the NAME array:
for /L %%i in (3,1,!numFields!) do (
for %%b in (!name[%%i]!) do echo %%b: !%%b!
)
)
)
Please note that the standard separators in FOR sets are comma, semicolon and equal-sign, besides spaces:
for %a in (one two,three;four=five) do echo %a
Previous program replace spaces by another character and use commas to separate fields. However, if the line may contain semicolons or equal-signs the fields will be splitted at that point, so in this case these characters must be changed for another ones before the FOR and recovered later, in the same way of the space.
EDIT: Modifications for new request (eliminate last comma)
Eliminating the last comma is not trivial, although not too complex neither. I hope my method be easy to understand; it is based on SET /P command behaviour of show text (the input prompt) with NO new line at end; note that the format is SET /P =text>>out<NUL. The <NUL part is needed so the SET /P will NOT wait for input; don't leave spaces before the < (the same as >>). However, this behaviour do NOT work in Windows Vista an later versions, I think. If the method don't work for you, then it must be modified again...
I also moved ahead and include some remarks about the parts that still are missing in your code (I think), that is, the processing of several files.
:proces
REM Executing loop for each file in current directory
REM *This may be done with a FOR loop:*
::*for %%F in (*.csv) do (*
REM *The file name is given by %%F. In this case, the fileinitialization part*
REM *must be done here, for example:*
set numFields=0
echo %creat%>fil.sql
REM Read the lines of the CSV file
For /F "eol==" %%A in (bio.csv) Do (
set "line=%%A"
REM check if index of array is 0
if !numFields! equ 0 (
REM First line, Store in array name
for %%B in (!line: ^=!) do (
REM Note that I changed the place of the ECHO command
set /A numFields+=1
set name[!numFields!]=%%B
if !numFields! equ 1 (
REM First field: show it with NO comma and NO NEW LINE
set /P =%%B (text^)>>%sqfile%<NUL
) else (
REM Next fields: complete the comma of previous field, WITH NEW LINE
echo ,>>%sqfile%
REM ... and show this field with NO comma and NO NEW LINE (again)
set /P =%%B (text^)>>%sqfile%<NUL
)
)
REM Insert the new line of last field (that have NOT comma :-)
echo/>>%sqfile%
)
)
::*)*
GOTO:EOF
:copydata
I strongly encourage you to keep my previous format: 4 justification columns inside each block of code enclosed in parentheses and place the closing parentheses in the same column of the opening command, FOR or IF. This format will help you to easily locate errors cause by mismatched parentheses in large programs.
Antonio

How to loop through files matching wildcard in batch file

I have a set of base filenames, for each name 'f' there are exactly two files, 'f.in' and 'f.out'. I want to write a batch file (in Windows XP) which goes through all the filenames, for each one it should:
Display the base name 'f'
Perform an action on 'f.in'
Perform another action on 'f.out'
I don't have any way to list the set of base filenames, other than to search for *.in (or *.out) for example.
Assuming you have two programs that process the two files, process_in.exe and process_out.exe:
for %%f in (*.in) do (
echo %%~nf
process_in "%%~nf.in"
process_out "%%~nf.out"
)
%%~nf is a substitution modifier, that expands %f to a file name only.
See other modifiers in https://technet.microsoft.com/en-us/library/bb490909.aspx (midway down the page) or just in the next answer.
You can use this line to print the contents of your desktop:
FOR %%I in (C:\windows\desktop\*.*) DO echo %%I
Once you have the %%I variable it's easy to perform a command on it (just replace the word echo with your program)
In addition, substitution of FOR variable references has been enhanced
You can now use the following optional syntax:
%~I - expands %I removing any surrounding quotes (")
%~fI - expands %I to a fully qualified path name
%~dI - expands %I to a drive letter only
%~pI - expands %I to a path only (directory with \)
%~nI - expands %I to a file name only
%~xI - expands %I to a file extension only
%~sI - expanded path contains short names only
%~aI - expands %I to file attributes of file
%~tI - expands %I to date/time of file
%~zI - expands %I to size of file
%~$PATH:I - searches the directories listed in the PATH
environment variable and expands %I to the
fully qualified name of the first one found.
If the environment variable name is not
defined or the file is not found by the
search, then this modifier expands to the
empty string
https://ss64.com/nt/syntax-args.html
In the above examples %I and PATH can be replaced by other valid
values. The %~ syntax is terminated by a valid FOR variable name.
Picking upper case variable names like %I makes it more readable and
avoids confusion with the modifiers, which are not case sensitive.
You can get the full documentation by typing FOR /?
Easiest way, as I see it, is to use a for loop that calls a second batch file for processing, passing that second file the base name.
According to the for /? help, basename can be extracted using the nifty ~n option. So, the base script would read:
for %%f in (*.in) do call process.cmd %%~nf
Then, in process.cmd, assume that %0 contains the base name and act accordingly. For example:
echo The file is %0
copy %0.in %0.out
ren %0.out monkeys_are_cool.txt
There might be a better way to do this in one script, but I've always been a bit hazy on how to pull of multiple commands in a single for loop in a batch file.
EDIT: That's fantastic! I had somehow missed the page in the docs that showed that you could do multi-line blocks in a FOR loop. I am going to go have to go back and rewrite some batch files now...
Expanding on Nathans post. The following will do the job lot in one batch file.
#echo off
if %1.==Sub. goto %2
for %%f in (*.in) do call %0 Sub action %%~nf
goto end
:action
echo The file is %3
copy %3.in %3.out
ren %3.out monkeys_are_cool.txt
:end
There is a tool usually used in MS Servers (as far as I can remember) called forfiles:
The link above contains help as well as a link to the microsoft download page.
The code below filters filenames starting with given substring. It could be changed to fit different needs by working on subfname substring extraction and IF statement:
echo off
rem filter all files not starting with the prefix 'dat'
setlocal enabledelayedexpansion
FOR /R your-folder-fullpath %%F IN (*.*) DO (
set fname=%%~nF
set subfname=!fname:~0,3!
IF NOT "!subfname!" == "dat" echo "%%F"
)
pause
Echoing f.in and f.out will seperate the concept of what to loop and what not to loop when used in a for /f loop.
::Get the files seperated
echo f.in>files_to_pass_through.txt
echo f.out>>files_to_pass_through.txt
for /F %%a in (files_to_pass_through.txt) do (
for /R %%b in (*.*) do (
if "%%a" NEQ "%%b" (
echo %%b>>dont_pass_through_these.txt
)
)
)
::I'm assuming the base name is the whole string "f".
::If I'm right then all the files begin with "f".
::So all you have to do is display "f". right?
::But that would be too easy.
::Let's do this the right way.
for /f %%C in (dont_pass_through_these.txt)
::displays the filename and not the extention
echo %~nC
)
Although you didn't ask, a good way to pass commands into f.in and f.out would be to...
for /F %%D "tokens=*" in (dont_pass_through_these.txt) do (
for /F %%E in (%%D) do (
start /wait %%E
)
)
A link to all the Windows XP commands:link
I apologize if I did not answer this correctly. The question was very hard for me to read.