I have this file structure where each subdirectory contains particular file types, lets say pdfs.
ParentDIR
-->SUBDIR1
-->SUBDIR2
I am trying to run a batch file from the parent to recursively return paths so I can parse them and perform some action
#echo off
for /R %%v in (*.pdf) do (
set pathname=%%~pv
echo %pathname%
)
I would expect the output of the path variable here to read
\PARENTDIR\SUBDIR1
\PARENTDIR\SUBDIR2
but it reads
\PARENTDIR\SUBDIR2
\PARENTDIR\SUBDIR2
If I echo the value of %%~pv without assigning it to a variable, it is correct.
How can I get the value of this variable to be assigned correctly at each iteration through the loop?
#echo off >Nul
setlocal EnableDelayedExpansion
for /R %%v in (*.pdf) do (
set pathname=%%~pv >Nul
echo !pathname!
)
endlocal
Here mind EnableDelayedExpansion keyword of setlocal command = Expand variables at execution time rather than at parse time, if used !pathname! syntax instead of %pathname% one.
Related
I have two .txt files. One contains numbers, and the other one contains filepaths. I want to combine these two files to a .csv. The combination is based on wether the number (from nrs.txt) is in the string of the filepath (nodups.txt).
Now I have the following code for this:
#setlocal enableextensions enabledelayedexpansion
for /F %a IN (Output\nrs.txt) DO (
SET "nrs=%a"
for /F %b IN (Output\nodups.txt) DO (
SET "pathstring=%b"
SET csvdelim=,
IF NOT x!pathstring:%nrs%=""!==x%pathstring% %nrs%,%pathstring%>>new2017.txt
)
)
#endlocal
However, I keep having the following issues with the code:
The pathstring never seems to get set. (when I run the code without the if statement, The nrs variable gets set but the pathstring is set to %b). I've seen a lot of possible solutions on here already but none seem to work for me (setting variables like !var! and using usebackq).
The IF statement in the second for loop gets the following error message =""!==x%pathstring% was unexpected at this time. The ="" should remove the nr. from the path (if its there). When I replace "" with something else it still does not work.
The file contents are:
File nrs.txt:
12345
12245
16532
nodubs.txt:
C:\tmp\PDF_16532_20170405.pdf
C:\tmp\PDF_1234AB_20170405.pdf
C:\tmp\PDF_12345_20170506.pdf
Desired output:
12345, C:\tmp\PDF_12345_20170506.pdf
16532, C:\tmp\PDF_16532_20170405.pdf
I really hope someone can help me out with this !
This solution use a different approach, based on arrays:
#echo off
setlocal EnableDelayedExpansion
rem Load array from nodubs.txt file
pushd "Output"
for /F "tokens=1,2* delims=_" %%a in (nodubs.txt) do set "nodubs[%%b]=%%a_%%b_%%c"
rem Process nrs.txt file and show output
(for /F %%a in (nrs.txt) do (
if defined nodubs[%%a] echo %%a, !nodubs[%%a]!
)) > new2017.txt
In a batch file for variables need two percent signs.
There is no need to put %%A into a variable, use it directly.
#setlocal enableextensions enabledelayedexpansion
for /F %%a IN (Output\nrs.txt) DO (
findstr /i "_%%a_" Output\nodups.txt >NUL 2>&1 || >>new2017.txt Echo %%a
)
#endlocal
Instead of a second for, I'd use findstr to search for the entry of nrs.txt enclosed in underscores.
if no find use condiotonal execution on failure || to write to the new file.
According to changed preliminaries another answer.
#Echo on
Pushd Output
for /F "tokens=1-3 delims=_" %%A IN (
' findstr /G:nrs.txt nodubs.txt'
) DO >>"..\new2017.txt" Echo %%B, %%A_%%B_%%C
Popd
sample output:
> type ..\new2017.txt
16532, C:\tmp\PDF_16532_20170405.pdf
12345, C:\tmp\PDF_12345_20170506.pdf
Although I'm really a newbie in this field, I want to accomplish a task in batch scripting: There is a determinate folder of company contracts in a determinate path, each of this folders (approx. 400) has a common folder (2016) where there might be a file indicating there has been an inspection in this year. What i want is to print every company folder that has not any file in the common 2016 folder and a count of the times this happens.
This is what i have (and does not work at all):
set c=0
for %i /d in (*) do
for %j in ($%i\2016\*) do
if (%j==NUL) then (#echo $%i c+=1 echo %c)`
If you just want to know if there is a file in the 2016 directory you can do this:
#echo off
SetLocal EnableDelayedExpansion
set count=0
for %%i /d in (*) do (
REM first unset variable
set files=
for %%j in (%%i\2016\*) do (
REM will set variable each time a file is encountered
set files=present
)
if not DEFINED files (
REM No files in directory 2016
echo %%i
set /a count+=1
echo !count!
)
)
EndLocal
exit /b 0
I don't see why you use $ before each %i. If you execute this code from the command line use one % for the loop variables i and j. But in a batch-script you'll have to use two of them (%%i, %%j).
Another thing, c+=1 won't work except if you use set /a.
I used delayed expansion because each block code ( between (...)) is parsed as one single command (as if it was all on one line with && between the commands inside the block) and you can't just assign a new value to a variable and read that new value in the same command. That's also the reason why I use !count! instead of %count% (which will give the value before the block). If you'd rather not use delayed expansion, remove the SetLocal EnableDelayedExpansion and replace echo !count! with call echo %%count%% (is another way to read a new value in the same command)
Also, be aware that each echo will end its output with a carriage retur and a newline. So each echo will result in a new line of output.
I have written below script:
#echo off
setlocal EnableDelayedExpansion
REM Collect source filenames from C:\Files and load into C:\doc.txt
dir C:\sources\Sourcefiles /b /a-d > C:\sourcefilenames.txt
REM fetch count of source files and store into variable count
For /F %%I in ('call C:\count.bat ') Do Set count=%%I
REM loop "count" number of times and echo temp.txt value
FOR /L %%A IN (1,1,%count%) DO (
REM call line.bat to fetch line 1,line 2 and so on of sourcefilenames.txt for each loop
call line.bat %%A>C:\temp.txt
set /p var=<C:\temp.txt
echo var:%var% ----------> returns previous run value
type C:\temp.txt ----------. returns current value of temp.txt
)
Basically what i am trying to do out of the above script is:
I am creating a variable(var) from the content of temp.txt(data in temp.txt will change for each time loop runs) to be used in multiple loops.
But the problem i am facing is :
Echo var is:%var% command returning me previous run value not temp.txt current content.whereas command "type C:\temp.txt" returning me temp.txt current content.
(Note: if i have called/created variable "var" from some other script it returns me that previous value else it returns Null)
Your help/guidance on above issue is really appreciated.
Thanks
I suppose the variable remains in memory, without being re-read.Attempts to limit the validity of the variable.
setlocal
echo something.....
endlocal
or #echo off & setlocal
When CMD.exe encounters a block of code in parentheses, it reads and parses the entire block before executing. This can cause unintuitive behavior. In this case, your echo var:%var% line is being parsed once at the beginning of the loop and never again.
The easiest fix for this is to change that line to
echo var:!var!
The !var! syntax is parsed every time through the loop. This works because you have enabledelayedexpansion set in your script.
Another workaround to this type of problem is to remove the parentheses and instead call out to a subroutine.
FOR /L %%A IN (1,1,%count%) DO call :loopLineBat %%A
... rest of script
exit /b
:loopLineBat
>%temp%\temp.txt call line.bat %1
<%temp%\temp.txt set /p var=
echo var:%var%
type %temp%\temp.txt
exit /b
This loop does the same as above, but because it is not in a parenthesized block, all of the lines are parsed and executed in order.
I am trying to assign the value of %%~nxK to variable t but it just seems impossible to do
FOR /D %%K in ("%APPDATA%\Mozilla\Firefox\Profiles\*") DO (
set "t=%%~nxK"
#echo t
)
pause
(note : There is only one folder present in \Profiles*)
I have also tried
set t="%%~nxK"
and
set t=%%~nxK
when trying to #echo t from within the loop or outside the loop I only see the letter "T" and no assigned values
setlocal enableDelayedExpansion
FOR /D %%K in ("%APPDATA%\Mozilla\Firefox\Profiles\*") DO (
set "t=%%~nxK"
#echo !t!
)
pause
in this case you need delayed epxansion
The syntax for print a variable in DOS is echo %t%
I have a batch with the following code:
SET CI=MySubDir
SET CIDIR=SomePath\..\..\%CI%
SET OutDir=MyOutDir
for /f %%G in ('dir /b %CIDIR%') do (
SET SCHEMADIR=%CIDIR%\%%G\schema
SET CATDIR=%CIDIR%\%%G\catalog
echo %%G
echo %SCHEMADIR%
echo %CATDIR%
if exist %SCHEMADIR% (
echo copy "%SCHEMADIR%" to "%OutDir%\..\Schema"
XCOPY /E /Y /I /Q /D %SCHEMADIR% "%OutDir%\..\Schema"
)
if exist %CATDIR% (
echo copy "%CATDIR%" to "%Outdir%\..\Catalog"
XCOPY /E /Y /I /Q /D %CATDIR% "%OutDir%\..\Catalog"
)
)
This program should copy all files within any sub-directory of SCHEMADIR or CATDIR to my OutDir (of course the files within my OutDir might be overridden several times depending on the existing ones within the source-directories).
When I echo the current file-name with echo %%G I get the sub-directory as wanted, curiously echoing either SCHEMADIR or CATDIR results in only the very last sub-directory found within CIDIR. So while %%Gresults in e.g. BE, SCHEMADIR results to SomePath\..\..\MySubDir\TH (where TH is the last sub-directory within MySubDir). What is whrong here?
In batch files, each line or block of lines (code inside parenthesis) is parsed, executed and the process repeated for the next line/block. During the parse phase, all variable reads are removed, being replaced with the value in the variable before the code starts to execute. If a variable changes its value inside the line/block, this changed value can not be retrieved from inside the same line/block as the variable read operation does not exist.
The usual way to solve it is to use delayed expansion. When enabled, you can change (where needed) the syntax from %var% to !var!, indicating to the parser that the read operation must be delayed until the command that uses the value starts to execute.
You can try this code to see it in action
#echo off
setlocal enabledelayedexpansion
set "test=initial value"
for %%a in (a b c) do (
rem Variable changed inside the block of code
set "test=%%a"
rem Retrieve data with normal expansion
echo Normal expansion: [%%a] [%test%]
rem Retrieve data with delayed expansion
echo Delayed expansion: [%%a] [!test!]
)
In your case, since SCHEMADIR and CATDIR are changed inside the block of code, to retrieve the changed value inside the same block you will need delayed expansion.