I have a problem removing trailing \ in a script, my current script is:
echo on
setlocal enableextensions enabledelayedexpansion
SET SCRIPTFOLDER=C:\install$
FOR /F "tokens=* delims=," %%a in (%SCRIPTFOLDER%\GetFilesandFoldersFromHere.Txt) DO (
set data.path=%%~pa
SET data.path=%data.path:~0,-1%
echo %data.path%
rem echo file and folder= %%~na%%~xa Folder=%data.path%
)
The GetFilesandFoldersFromHere.Txt file has lines of files and location e.g.:
T:\First File Here\Move this File.txt
When I run the above code I get:
C:\install$\file Archive Scripts>(
set data.path=\First File Here\
rem If ~-1data.path:~0,0
SET data.path=~0,-1
echo
rem echo file and folder= Move this File.txt Folder=
I want to assign data.path the directory (without drive letter and the trailing ). It assigns the value but when I try to get rid of the trailing \ the value is nulled.
Does anyone have an idea whta is wrong with the code? I am sure it is a simple solution. Been banging my head against this screen, can't see the woods from the tree at the moment.
The problem is that when the for code block (the code enclosed in parenthesis) is parsed, all the variable read operations are replaced with the value in the variable before starting to execute, and in each iteration what is used is this initial value, and not the value stored into the variable during the execution.
If you change a variable inside a block of code and need to access the changed value inside the same block of code, you need to enable delayed expansion (setlocal enabledelayedexpansion) and change (where necessary) the syntax to access the variables to use !varName! instead of %varName%. This indicates to the parser that this read operation must be delayed.
So, in your code you have delayed expansion enabled, but
SET data.path=%data.path:~0,-1%
echo %data.path%
should be something like
SET data.path=!data.path:~0,-1!
echo !data.path!
Here's a trick to remove the trailing backslash
#echo off
set "folder=c:\data\"
for %%a in ("%folder%\.") do set "folder=%%~dpnxa"
set fold
pause
Related
I have a simple text file containing one file name per file. I want to merge all of these files. My plan for this was to read the text file, build a string like "filename1+file2+f3" and then use that as a parameter to copy /b.
However, I am having trouble reading the file correctly.
Here is what I have right now:
SET x=
FOR /F %%G IN (merge.txt) DO SET x=%x%+%%G
ECHO %x%
However, the "recursion" here does not seem to work properly and %x% just gets set to "+fl", where fl is the last filename in the file.
How do I do this properly?
Your logic is correct, but you are just missing the delayed expansion usage.
SETLOCAL EnableDelayedExpansion
SET "x="
FOR /F %%G IN (merge.txt) DO SET x=!x!+%%G
ECHO %x%
REM Trim the leading +
SET x=%x:~1,999%
ECHO %x%
ENDLOCAL
Without the delayed expansion, %x% is only evaluated when the FOR loop starts, so it would be blank for each iteration. By enabling delayed expansion, !x! (the notation for this) is evaluated on each iteration so it will build the compound string you are looking for.
How to get selected character
for %%A in (controls\vbalSGrid6.ocx) do (
SET TEXT=%A%
SET SUBSTRING=%TEXT:~9%
echo %SUBSTRING%
)
this is giving echo is off but i only need vbalsgrid6.ocx.
The direct way
set "text=controls\vbalscrid6.ocx"
set "substring=%text:~9%"
No need for the for command, unless you are iterating over a set of files or you don't want to use substring operations to get file names
The easy way to get the name and extension of the file
for %%a in (controls\vbalsgrid6.ocx) do set "fileName=%%~nxa"
%%a hold a reference to the file, and %%~nxa is the file name and extension of the referenced file
A direct translation/corrected version of your code (in this case, iterating over the list of files, but not needed)
#echo off
setlocal enableextensions enabledelayedexpansion
for %%a in (controls\*.ocx) do (
set "text=%%a"
set "substring=!text:~9!"
echo !substring!
)
When the batch parser reaches a line/block of code (code inside parenthesis), the full line/block is checked searching the places where a variable will be readed. All this reads are replaced with the value stored in the variable at parse time, before the line/block is executed. That means that if a variable changes its value inside a block, this changed value can not be accessed from inside the same block as the read operation on the variable was previously replaced with the initial value stored inside it.
To handle this case, delayed expansion is used. When delayed expansion is enabled, it is possible to change (where needed) the syntax to read a variable, from %var% to !var!, indicating to the parser that this read operation should be delayed until the command is executed.
The included code will work while there is no ! in the name of the files. As delayed expansion is active, the parser will try to interpret any !, giving non expected results in some cases. It can be handled but sometimes it can be a bit tricky.
#echo off
setlocal enableextensions disabledelayedexpansion
for %%a in (controls\*.ocx) do (
rem Retrieve the initial text. No problem as delayed expansion is disabled
set "text=%%a"
rem Enable delayed expansion to read the value in %text%. And ensure
rem it is disabled at the moment of the assignment to the substring var
setlocal enabledelayedexpansion
set "substring="
for /f "delims=" %%b in ("!text:~9!") do (endlocal & set "substring=%%b")
rem We need delayed expansion enabled to read the changed value
rem If substring is empty, the previous endlocal was not executed and
rem there is no need for a new setlocal
if defined substring setlocal enabledelayedexpansion
echo(substring value=!substring!
endlocal
)
It's a simple bat script that should checkout some folders from svn . I'm not that up on bat scripting, there seems to be no consistency on how variables are referenced.
For instance the variable "branchV" does not get appended it is seen as '""', but if I echo it I see the user input.
set "DB_DIRECTORIES=AuditUser-db CarrierProcessingRules-db iDetectDB-db iRisk-db WarningsIndex-db"
set "SVNBASEURL=http://XX.XX.XX.XX:7777/svn/YYY"
set BASELOCALDIRECTORY="C:"
#echo on
#cls
#echo Check out DB directories from?
#echo
#echo 1. Trunk
#echo 2. Branch
#echo
#echo
#set OPTIONSELECTED=
#set /P OPTIONSELECTED=SELECT OPTION:%=%
if "%OPTIONSELECTED%" == "1" (
set SVNURL="%SVNBASEURL%/trunk"
set BRANCHV="BCSTrunk"
) ELSE IF %OPTIONSELECTED% == 2 (
#echo
#echo
#echo
#echo PLEASE ENTER THE BRANCH VERSION YOU WISH TO CHECKOUT
#echo
#echo
#set branchV=
#set /P branchV=ENTER VERSION:%=%
#echo
set SVNURL="%SVNBASEURL%"/branches/"%branchV%"
) ELSE (
#echo Invalid option
)
for %%i in (%DB_DIRECTORIES%) do (
set PATHTOUSE="%BASELOCALDIRECTORY%"/"%branchV%"/%%i
set NEWSVNURL="%SVNURL%"/%%i
REM Intended to remove all inverted commas , which were causing an issue in svn
set PATHTOUSE="%PATHTOUSE:=%"
set NEWSVNURL=%NEWSVNURL:=%
TortoiseProc.exe /command:checkout /path:%PATHTOUSE% /url:%NEWSVNURL% /closeonend:1
)
In batch scripts, when a line or a block of code (the code enclosed in parenthesis) is reached, all variable reads are replaced with the value they have before starting to execute that line or block. So, if you change a variable inside a block, you can not retrieve this value inside the same block. There are no reads of the variable value, they were replaced with its values.
To correctly retrieve the changed value inside the same block, it is necessary to indicate to cmd that the read operations should be delayed until the line is executed. To do this, two steps are necessary. First is enable this option
setlocal enabledelayedexpansion
When it is enabled, variables that should be read delayed need the sintax !var! instead of %var%
I'm creating a simple production environment for work and in doing so need to set specific environment variables for specific projects in batch file.
Here's what i want to achieve:
1) Define a single environment variable which would define a list of directories
2) Recurse down each directory and add all leaf folders to a final environment variable.
[EDIT] After looking back at what i originally posted i was able to remove some redundancy. But the "The input line is too long." error occurs when %LINE% gets too long. Using the short path expansion does help but it can still error out. I'll look at how to break the echo to a temp file next as suggested.
Here's what i currently have:
#echo off
set RECURSE_THESE_DIRS=C:\Users\eric\Autodesk
set TMP_FILE=%CD%TMP_FILE.%RANDOM%.txt
setLocal EnableDelayedExpansion
for %%i in (%RECURSE_THESE_DIRS%) do (
if exist %%~si\NUL (
for /f "tokens=*" %%G in ('dir /b /s /a:d %%i') do set LIST=!LIST!;%%G
)
)
set LIST=%LIST:~1%
rem !!! AT THE ECHO LINE BELOW IF %LIST% IS TOO LONG, THIS SCRIPT FAILS
rem !!! WITH The input line is too long. ERROR :(
echo %LIST%>%TMP_FILE%
endlocal
for /F "delims=" %%G in (%TMP_FILE%) do set FINAL_VAR=%%G
del /F %TMP_FILE%
So by setting RECURSE_THESE_DIRS to directories i wish to parse, i end up with a %FINAL_VAR% which i can use to specify paths for proprietary software i use. Or i could use this script to append to %PATH%, etc...
This works for me but i would love suggestions to improve/streamline my script?
The root of your problem is that batch is limited to fit the variable name, contents and = into 8192 bytes, hence your directory-list simply isn't going to fit into one variable.
Personally, I'd just spit out a dir/s/b/a-d list to a tempfile and process that file with a for/f "delims=" - after all, you'd be likely to need to process your ;-separated envvar similarly in whatever process you are proposing to execute.
For instance, here's a test producing the same error - not using filenames at all
#ECHO OFF
SETLOCAL
SET "var=hello!1234"
SET var=%var%%var%%var%%var%%var%
SET var=%var%%var%%var%%var%%var%%var%%var%%var%
SET var=%var%%var%%var%%var%%var%
SET var=%var%%var%%var%%var%
SET count=8000
:loop
SET /a count +=1
ECHO %count%
SET var=%var%x
ECHO %var%
GOTO loop
GOTO :EOF
This should fail where count=8184.
Suggestions:
Use for /d /r to handle the recursion
Maybe i'm wrong, but in your script, you traverse the directory hierarchy, adding each directory to temp file which is then readed to concatenate its lines into a variable which is then writed to temp file, to be read again in another variable. If concatenation of directories fit into a variable, why not concatenate them without any temporary file?
If concatenation is in the limit of line length, as suggested by npocmaka, and if soported by end application, user short paths. Also, instead of adding the new values in the same instruction (not line) that contains the for loop, use a call to a subrutine with the new value passed to it, and then append the value. It's slower, but command lines executed will be shorter.
I'd like to put each of the many properties' file names into variable fileName and echo them out to the command prompt window. But only the last properties file name to be cycled thru is printed out as many times as there are properties files. Is there an easy fix to this problem. I know that ...DO echo %%-nxG can do the same thing but I'd like to save the file name in %%~nxG for future use.
FOR %%G IN (C:\ExecutionSDKTest_10.2.2\*.properties) DO (
set fileName=%%~nxG
echo %fileName%
)
You need to use delayed expansion:
setlocal enabledelayedexpansion
FOR %%G IN (C:\ExecutionSDKTest_10.2.2\*.properties) DO (
set fileName=%%~nxG
echo !fileName!
)
Environment variables in cmd are expanded when a command is parsed – in this case this includes the whole block in parentheses. So %fileName% gets replaced by an empty string because it didn't have a value before the loop ran. Delayed expansion uses ! instead of % and changes variable evaluation so that they are evaluated just before a command is run.
help set has more details about why and when it is necessary. In general, whenever you modify and use a variable within a loop you have to use delayed expansion, but it comes with a few other benefits too.