batch : Substring in loop with 2 variables - batch-file

I have a loop that loops over files, gets the actual file name (not including the whole path) and tries to check if that file name exists in some list.
the code I have is:
setlocal enabledelayedexpansion enableextensions
for /R %%j in (*.c) do (
set MYVAR=%%j
set actualFileName=%%~nj
if NOT "%MY_FILE_LIST%"=="!MY_FILE_LIST:%actualFileName%=!" set "TOCOMPILE=!TOCOMPILE! %MYVAR%"
this code does not work since the actualFileName is accessed with % instead of !.
but !MYVAR:~!actualFileName!! doesn't work either.
what can i do?

You can directly use the for replaceable parameter modifiers to get the needed information
for /r %%j in (*.c) do (
echo actualFileName is %%~nj
)
Where %%~nj is the name, without extension, of the file being referenced in %%j. See for /? for the full list
edit to adapt to comments
setlocal enableextensions enabledelayedexpansion
for /r %%j in (*.c) do (
if not "!MY_FILE_LIST:%%~nj!"=="%MY_FILE_LIST%" (
set "TOCOMPILE=!TOCOMPILE! "%%~fj""
)
)
This should do the job IF no file contains a exclamation in its name. If this can not be ensured
setlocal enableextensions disabledelayedexpansion
for /r %%j in (*.c) do (
setlocal enabledelayedexpansion
if not "!MY_FILE_LIST:%%~nj!"=="%MY_FILE_LIST%" (
for /f "delims=" %%a in ("!TOCOMPILE! ") do (
endlocal
set "TOCOMPILE=%%a"%%~fj""
)
) else endlocal
)

setlocal enabledelayedexpansion enableextensions
for /R %%j in (*.c) do (
set MYVAR=%%j
set lastIndex= some calculation to find last index of /
for /f "tokens=* delims=" %%# in ("!lastIndex!") do (
set actualFileName=!MYVAR:~%%#!
)
)
use another nested FOR

Related

pass outer loop variable into nested loop

So my mission is to loop through a directory and set a variable to capture the zip file name.
then use that variable to parse what is on the left of the string before the underscore. That way I can name a log file. I searched high and low but I'm not seeing any good examples on Stack. when I use %%i it will return a full directory path. (which is not needed here.) If I use the %%z I get null back how can I pass my %zipfile% variable into my nested loop In()?
setlocal enableextensions enabledelayedexpansion
set dir1="C:\test\"
set 7zip="C:\Program Files\7-Zip\7z.exe"
set output="C:\test\Filelist.txt"
REM enter folder location
cd C:\test
REM loop through zip files
for /r %%i in (*.zip) do ( set zipfile=%%~nxi
for /F " delims=_" %%z in (%zipfile%) do (set log="%%z_file_list.txt")
)
Pause
REM Del %log%
Does the following help you out?
#Echo Off
SetLocal EnableExtensions DisableDelayedExpansion
Set "dir1=C:\test"
Set "7zip="%ProgramFiles%\7-Zip\7z.exe"
Set "output=C:\test\Filelist.txt"
For /F "Delims=" %%G In (
'Set "PATHEXT=" ^& %SystemRoot%\System32\where.exe /F /R "%dir1%" "?*_*.zip" 2^>NUL'
) Do (
For /F "Delims=_" %%H In (
"%%~nG"
) Do (
Echo Set "log=%%H_file_list.txt"
)
)
Pause

Loop through files in folder, replace content and Save as new Name

I need to loop through filed end with .edi in my folder, replace a character in the content and then save the file in another folder with "_updated"on the end.
e.g.
C:/Test/FileName.edi replace ' in file with ^ and save the file into C:/Test/Output/FileName_Updated.edi
I've tried the following code and it works up until the saving the filename part, I've got confused somewhere, I don't usually write batch scripts:
#echo off
setlocal enabledelayedexpansion
for %%f in (C:\Test\*.edi) do (
set "input=C:\Test\"
SET "output=C:\Test\Output\"
for %%a in (%%f) do (
set "output=%output%%%~na_update.%%~xa"
)
(for /f "delims=" %%i in (%%f) do (
set "line=%%i"
setlocal enabledelayedexpansion
set "line=!line:'=^!"
echo(!line!
endlocal
)))>> %output%
)
Figured it out with help from aschipfl
#echo off
setlocal enabledelayedexpansion
for %%f in (C:\Users\CHRW\Desktop\EDILocalTest\*.edi) do (
SET "output=C:\Users\CHRW\Desktop\EDILocalTest\Output\"
for %%a in (%%f) do (
set "outputfile=!output!%%~na_update%%~xa"
)
(for /f "delims=" %%i in (%%f) do (
set "line=%%i"
setlocal enabledelayedexpansion
set "line=!line:'=^!"
echo(!line!
endlocal
))>> !outputfile!
)
#echo off
setlocal enabledelayedexpansion
for %%f in (C:\Test\*.edi) do (
set "input=C:\Test\"
SET "output=C:\Test\Output\"
(for /f "delims=" %%i in (%%f) do (
set "line=%%i"
rem setlocal enabledelayedexpansion
set "line=!line:'=^!"
echo(!line!
rem endlocal
)))>> "%output%%%~nf_update.%%~xf"
)
Since you were changing the value of output within the loop, the redirection should have been to !output! not %output% - the changed value of output, not the value of output at the time the outer for loop was parsed.
Since %%f contains a filename, there's no need to re-parse it. Easier to construct the output filename in-line
Since delayedexpansion has been invoked at the start of the procedure, there's no need to re-invoke it and close the new invocation. I've REMmed-out those lines as it may be that you are presenting abbreviated code.

Batch get filename from path

Hi I don't have much experience in batch-programming and have a problem. I have a .bat script that reads a file with a list of paths and i want to get the filename of these paths. I use the script in cygwin.
My code in the Script:
for /F %%a in (error1.txt) do (
set value=%%a
FOR /F %%I IN ("%value%") DO SET MYPATHFILE=%%~nxI
)
When i run the Script %value% is empty.
Value of error1.txt:
a/b/c/d/TextIWant
you need delayed expansion or you can directly use %%a:
for /F %%a in (error1.txt) do (
FOR /F %%I IN ("%%a") DO SET MYPATHFILE=%%~nxI
)
or
setlocal enableDelayedExpansion
for /F %%a in (error1.txt) do (
set value=%%a
FOR /F %%I IN ("!value!") DO SET MYPATHFILE=%%~nxI
)
It looks like you will need Delayed Expansion.
The current problem is, that you want to use a variable in the same set of brackets where you changed the value in (the surrounding For-Loop).
Add setlocal EnableDelayedExpansion to your code at the top and change the %value% to !value!
You can test the problem yourself with this code:
#echo off
setlocal EnableDelayedExpansion
set foo=bar
For /L %%a (1,2,1) do (
set foo=foobar
echo.old value %foo%
echo.new value !foo!
)
I hope it helped :)
Greetings
geisterfurz007

list directories which do not start with

I want to echo all directories which do not starts let's say with a letter. I write following snippet
#echo off
for /d %%g in (*) do (
echo %%~nxg
)
and it prints out all directories. How should I filter out those starts with a? I'm trying do something with IF-Statement, but fail miserably.
Output filtering
dir /ad /b | findstr /i /v /b "a"
List the directories (/ad) and pipe (|) the output of the command into findstr, that will select the lines that does not contain (/v) at the beginning (/b) the string "a", case insensitive (/i)
Substring
#echo off
setlocal enableextensions enabledelayedexpansion
for /d %%a in (*) do (
set "name=%%~na"
if /i not "!name:~0,1!"=="a" echo %%a
)
for replaceable parameters do not allow the use of substring operations, so a variable is needed. But as the variable is changed inside a block of code (code in parenthesis) and normal variable expansion is done when the block is parsed, not when it is executed, delayed expansion is needed to retrieve (read) the value from the changed variable.
The problem with this code is it will fail when folder's names contain ! as it will be consumed by the parser in the set command. To handle it, delayed expansion should be enabled/disabled when needed
#echo off
setlocal enableextensions disabledelayedexpansion
for /d %%a in (*) do (
set "name=%%~na"
setlocal enabledelayedexpansion
for %%b in ("!name:~0,1!") do (
endlocal
if /i not "%%~b"=="a" echo %%a
)
)
Character removal
#echo off
setlocal enableextensions disabledelayedexpansion
for /d %%a in (*) do (
for /f "tokens=* delims=aA" %%b in ("a%%a") do (
if /i "%%~b"=="%%~a" echo %%a
)
)
Here a for /f is used, configured to see the letters aA as delimiters but to retrieve all the tokens. This will make the for /f remove all the delimiters (aA) from the start of the line. If the remaining data is equal to the initial data, the name of the folder does not start with a or A
for /d %%g in (*) do (
for /f "eol=a tokens=* delims=" %%# in ("%%~nxg") do echo %%~fg
)
To do it with an IF, try this:
#ECHO OFF
SetLocal EnableDelayedExpansion
FOR /D %%g IN (*) DO (
SET tmp=%%~nxg
IF NOT "!tmp:~0,1!"=="a" (
ECHO %%~nxg
)
)

Loop through CSV file with batch - Space issue

I have a csv file like this
name,sex,age
venu,m,16
test,,22
[EDIT]
name could have comma also
"venu,gopal",m,16
I want to handle if sex is nothing and save it to another file.
I have a script like this
#Echo Off
For /F "usebackq tokens=1-3 delims=," %%a in (test.csv) Do (
echo %%a, %%b, %%c >> test-new.csv
)
But for the third record, I am getting %%b as 22 which should be space. How to fix this?
[EDIT2]
I have tried as per that link. I am not sure what I am doing wrong. I am getting same issue. Please check it once.
#echo off
setlocal DisableDelayedExpansion
For /F "usebackq tokens=1-3 delims=" %%x in (C:\somefile.csv) Do (
setlocal EnableDelayedExpansion
set "var=%%x"
set "var=!var:"=""!"
set "var=!var:^=^^!"
set "var=!var:&=^&!"
set "var=!var:|=^|!"
set "var=!var:<=^<!"
set "var=!var:>=^>!"
set "var=!var:,=^,^,!"
set var=!var:""="!
set "var=!var:"=""Q!"
set "var=!var:,,="S"S!"
set "var=!var:^,^,=,!"
set "var=!var:""="!"
set "var=!var:"Q=!"
For /F "tokens=1-3 delims=," %%a in ("!var:"S"S=","!") Do (
endlocal
echo %%~a, %%~b, %%~c
setlocal EnableDelayedExpansion
pause
)
endlocal
)
This is a bit tricky, as multiple delims will be condensed to a single delim.
So you need to replace them before to a unique delim sequence.
#Echo Off
setlocal DisableDelayedExpansion
For /F "usebackq tokens=1-3 delims=" %%a in (test.csv) Do (
set "line=%%a"
setlocal EnableDelayedExpansion
set "line="!line:,=","!""
For /F "tokens=1-3 delims=," %%a in ("!line!") Do (
echo %%~a, %%~b, %%~c
)
)
This enclose each column into quotes, and with the %%~a the quotes will be removed later
EDIT: The solution for embedded commas
In this case it's only a bit different than the solution for how to split on ';' in CMD shell
#echo off
setlocal DisableDelayedExpansion
For /F "usebackq tokens=1-3 delims=" %%x in (test.csv) Do (
set "var=%%x"
setlocal EnableDelayedExpansion
set "var=!var:^=^^!"
set "var=!var:&=^&!"
set "var=!var:|=^|!"
set "var=!var:<=^<!"
set "var=!var:>=^>!"
set "var=!var:,=^,^,!"
rem ** This is the key line, the missing quote is intention
call set var=%%var:""="%%
set "var=!var:"="Q!"
set "var=!var:^,^,="C!"
set "var=!var:,,=,!"
set "var=!var:""="!"
set "var="!var:,=","!""
for /F "tokens=1-3 delims=," %%a in ("!var!") do (
endlocal
set "col1=%%~a"
set "col2=%%~b"
set "col3=%%~c"
setlocal EnableDelayedExpansion
if defined col1 (
set "col1=!col1:"C=,!"
set "col1=!col1:"Q="!"
)
if defined col2 (
set "col2=!col2:"C=,!"
set "col2=!col2:"Q="!"
)
if defined col3 (
set "col3=!col3:"C=,!"
set "col3=!col3:"Q="!"
)
echo a=!col1!, b=!col2!, c=!col3!
endlocal
)
)
using a string editor like SSED, I have overcome this issue by creating a temp file where I have replaced ",," with ",-," twice, then regarding a "-" as having been an empty field in the original file...
ssed "s/,,/,-,/ig;s/,,/,-,/ig" file1.csv > file1.tmp
Then the tokens are allocated correctly. If you need to edit the temp file and then return to a CSV, then use...
ssed "s/,-,/,,/ig;s/,-,/,,/ig" file1.tmp > file1.csv
This seems much simpler than doing in flight string replacements by token and having subroutines/etc.

Resources