EDIT: I have solved my problem based on suggestions from npocmaka and magoo. Now that i understand it is indentation that caused this, can you guys please suggest how i make my code cleaner in future?
Here's my bat file:
#echo off
setlocal enabledelayedexpansion
rem set lang pre-requisites
rem Purpose can be 'test' or 'deploy'
SET purpose="test"
SET lang="English-India"
SET lang_code="EnIn"
rem if purpose is test then the folder will be EnInP101M2Tsub, if purpose is deploy then EnInP101M2DFull
if "%purpose%"=="test"( SET folder=="%lang_code%P101M2Tsub" )
else if "%purpose%"=="deploy"( SET folder=="%lang_code%P101M2DFull" )
rem set required paths here
SET audio="C:\Users\Administrator\..path..\%lang%\%purpose%\BGM\M2\%folder%\*.wav"
SET source="C:\Users\Administrator\Downloads\Matt_Trial\..path..\%lang%\%purpose%\BGM\M2"
SET target="C:\Users\Administrator\Downloads\Matt_Trial\..path..\%lang%\%purpose%\BGM\M3\*"
rem copying the data
xcopy %source% %target% /e /i /h
rem copying audio files into the other folders
for /d %%a in (%target%) do copy %audio% "%%a"
rem renaming M3 folders
cd %target%
for /d %%a in (*) do (
set "p=%%a"
set "fp=!p:~0,8!" & set "tp=!p:~10!"
ren %%a !fp!M3!tp!
)
** For your Understanding **
I have 2 folders in my parent folder (M1,M2,M3).
Step 1: I am copying contents in M2 to a new folder M3.
Step 2: I need to copy contents of a folder under M2 which has my audio into all the folders in M3.
Step 3: I rename the folders under M3.
I hope I made myself clear.
I have to figure out the audio path based on the set variables. I need help with the if condition part. As of now I keep getting The system cannot find the file specified. Please help!!
A few errors.
SET will INCLUDE " after the = EXCEPT if you are using `SET "var=data" which is used to ensure that trailing spaces on the line are not included in the data assigned.
Any character after the = will be included (some need to be 'escaped' if they have a special meaning to batch, so set var==data will include the second = in the data assigned.
You haven't fallen into the spaces-in-variables trap - the syntax set var =data will set a variable named varspace not var.
There must be a space (strictly a separator, I believe) between the second operand of an IF statement and ( (if used)
Similarly, the ELSE clause must be )SpaceelseSpace( - all on the same line. This sequence of characters cannot be broken.
In your IF, you are using "%purpose%" Since purpose us set to "test" then this will be evaluated as ""test"", which is likely to be confusing, hence don't include " in your data assigned unless you have a really good reason.
I don't have 50 rep yet so have to comment via answer instead.
When i run into issues with my batch files I find it helpful to REM the #ECHO OFF line.
Then create a short-cut to the batch file and change the 'Target' field to pipe the output to a text file.
So, if your batch is at C:\test\mybatch.bat then create a shortcut to the batch in C:\test\
Next right-click the shortcut and select 'Properties'.
Under the 'Shortcut' tab, add the following to the end of the text in the target field..
>>output.txt
Run the shortcut which will save all the commands and errors to the output.txt file where you can see what is causing the issue, such as a variable not being set.
This:
#echo off
setlocal enabledelayedexpansion
rem set lang pre-requisites
rem Purpose can be 'test' or 'deploy'
SET purpose="test"
SET lang="English-India"
SET lang_code="EnIn"
rem if purpose is test then the folder will be EnInP101M2Tsub, if purpose is deploy then EnInP101M2DFull
if "%purpose%"=="test"( SET folder=="%lang_code%P101M2Tsub" )
else if "%purpose%"=="deploy"( SET folder=="%lang_code%P101M2DFull" )
Rather should look like (as you have only two options..)
#echo off
setlocal enabledelayedexpansion
rem set lang pre-requisites
rem Purpose can be 'test' or 'deploy'
SET "purpose=test"
SET "lang=English-India"
SET "lang_code=EnIn"
rem if purpose is test then the folder will be EnInP101M2Tsub, if purpose is deploy then EnInP101M2DFull
if "%purpose%"=="test" (
SET "folder=%lang_code%P101M2Tsub"
)
if "%purpose%"=="deploy" (
SET "folder=%lang_code%P101M2DFull"
)
echo %folder%
endlocal
You cannot start a line with else and set does not work properly with double = . And your comparisons are not correct as you have a quotes in variable values.
You have to use round parenthesis. Remember that if .... ( and ) else ( are inextricably linked to a single line (Each one has to be in a single line).
...
if "%purpose%"=="test" (
SET "folder=%lang_code%P101M2Tsub"
) else (
if "%purpose%"=="deploy" (
SET "folder=%lang_code%P101M2DFull"
)
)
...
Note:
I found extra issues in your set assignment:
Extra equal.
Double quotes.
Suppose Lang_code is equals to -EN-
SET folder=="%lang_code%P101M2Tsub"
Echo [%folder%]
It shows
[="-EN-P101M2Tsub"]
The correct way should be:
SET "folder=%lang_code%P101M2Tsub"
Echo [%folder%]
It shows
[-EN-P101M2Tsub]
Related
everything in my code is working fine except the last part.
I am wanting to output each text file to the folder with the same name. It is outputing the three text files into the one folder PentahoOutputs. However I am wanting to output it as the following:
folder system2.object2.assets contains file system2.object2.assets
folder system3.object3.assets contains file system3.object3.assets
folder system4.object4.assets contains file system4.object4.assets
#echo off SetLocal EnableDelayedExpansion
SET DELIMS=,
SET COMMAND=AddChange
SET EN=EN
SET ASSETS=Assets
SET DIREC = C:\Users\user.username\Documents\Training\BatchFiles\PentahoOutputs\
SET DELIMS2=.
FOR /D %%a IN (C:\Users\user.username\Documents\Training\BatchFiles\PentahoOutputs\*) DO ( SET subdirs=%%a
result=!subdirs:~71,7!
result2=!subdirs:~79,7!
set "concats=!result!!delims!!result2!!DELIMS!!COMMAND!!DELIMS!!EN!"
echo !concats!
echo !CONCATS! >>C:\Users\user.username\Documents\Training\BatchFiles\PentahoOutputs\!result!!delims2!!result2!!delims2!!assets!.CSV
)
PAUSE>NUL
edit ********** below
changing the problem code to the following puts each of the three files in each of the three folders... however i want one file in each folder
for /d %%b in (C:\Users\usre.username\Documents\Training\BatchFiles\PentahoOutputs\*) DO ( echo !CONCATS! >>%%b\!result!!delims2!!result2!!delims2!!assets!.csv )
From your posted code - given aschipfl's change as noted (although you don't attempt to use direc)
Your posted code has been mangled in an attempt, I assume, to disguise usernames. It also appears that you've cut down the actual code to show only the relevant section. This is good and understandable (but your edit has a glaring typo in the code - which is why you should cut-and-paste as far as possible.)
So - the setlocal following the #echo off must be separated by a & command-concatenator or be (my preference) on a separate line.
Within your for ... %%a ... block, you've removed the required set keyword for result*.
The fixed values you've used for substringing don't suit the changes you've made to the pathname, so the result in result is (eg) "tem3.ob"
If a value does not change within a block (like delims) then it's probably best to use %delims% - result changes, so you'd use !result! not %result%. !delims! also works, of course - but using the delayed-expansion form primes the reader to believe it's going to vary. (opinion)
'tis best with a string assignment to use set "var=value" as the quotes ensure that stray trailing spaces are not included in the value assigned. You only ever need to have that happen once...
OK - here's a revision
#echo OFF
SetLocal
SET DELIMS=,
SET COMMAND=AddChange
SET EN=EN
SET ASSETS=Assets
SET DIREC=U:\Users\user.username\Documents\Training\BatchFiles\PentahoOutputs\
SET DELIMS2=.
FOR /D %%a IN (%direc%*) DO (
FOR /f "tokens=1,2,3 delims=." %%p IN ("%%~nxa") DO IF /i "%%r"=="%assets%" (
echo %%p%delims%%%q%DELIMS%%COMMAND%%DELIMS%%EN%
echo %%p%delims%%%q%DELIMS%%COMMAND%%DELIMS%%EN% >> %%a\%%~na.CSV
)
)
GOTO :EOF
Note that I've used U: for the test directory (it's a ramdrive on my machine)
Given the outer loop, %%a is assigned the full pathname to the directory.
Since you imply that your target directorynames are system2.object2.assets then %%~nxa (the Name and eXtension of %%a) conveniently holds this string. Parsing that using delims of . and selecting the first 3 tokens would assign system2 to %%p, object2 to %%q and assets to %%r This avoids the substringing problem and permits system and object to be any length - not just 7.
The if statement ensures that the main block for for...%%p is only executed for directories found which fit ..asset (/i makes the if case-insensitive)
The required line can then be constructed from the metavariables and constants, as can the destination filename, so the enabledelayedexpansion is not required.
My task is to create a script to copy dated sub folders from within folders to another location. The base folders are named 16 hex characters, each has a folder for the year, inside a folder for the month, and inside that a folder for a date, which contains binary (dump) files I need to copy out. There are about 50 folders with around 5 days across two months that I care about (for now), so I want to capture something like the following:
C:\DUMPS\2401010153783FB6\2016\09\29*.*
Rather than doing a ton of copypaste script or manually trying to get all the folders I want (human error prone), I thought I should be able to create a BAT file to loop through an array of folder names and get at the files I care about. I found a very helpful piece in the answer from user DSS at the following:
How to loop through array in batch?
My problem is that his example shows how to use CALL ECHO instead of just ECHO, but I want to use the string value as part of a folder name, not just print to the console. Here's the work-in-progress code I've developed:
SET COPYPATH=C:\Dumps
SET DESTPATH=D:\NewDumps
SET FOLDERNAME[0]=2401010153783FB6
SET FOLDERNAME[1]=2401010753BBBBCE
SET "X=1" # array start from index 1
:Looping
IF DEFINED FOLDERNAME[%X%] (
CALL ECHO %%FOLDERNAME[%X%]%% REM Works great, I see the value of FOLDERNAME[0] on console.
SET TEMPVAR= CALL ECHO %%FOLDERNAME[%X%]%% REM No good! Result is CALL ECHO.
SET TEMPVAR= CALL %%FOLDERNAME[%X%]%% REM No good! Result is CALL X.
SET TEMPVAR= %FOLDERNAME[%X%]% REM No good! Result is literal FOLDERNAME[0]; I want the value of FOLDERNAME[0].
IF EXIST %TEMPVAR%\2016\09\28 (
COPY %TEMPVAR%\2016\09\28 %DESTPATH%\%FOLDERNAME[%X%]%%\2016\09\28
)
IF EXIST %COPYPATH%\%FOLDERNAME%\2016\09\29 (
COPY %COPYPATH%\%FOLDERNAME%\2016\09\29 %DESTPATH%\%FOLDERNAME%\2016\09\29
)
IF EXIST %COPYPATH%\%FOLDERNAME%\2016\09\30 (
COPY %COPYPATH%\%FOLDERNAME%\2016\09\30 %DESTPATH%\%FOLDERNAME%\2016\09\30
)
IF EXIST %COPYPATH%\%FOLDERNAME%\2016\10\01 (
COPY %COPYPATH%\%FOLDERNAME%\2016\10\01 %DESTPATH%\%FOLDERNAME%\2016\10\01
)
IF EXIST %COPYPATH%\%FOLDERNAME%\2016\10\02 (
COPY %COPYPATH%\%FOLDERNAME%\2016\10\02 %DESTPATH%\%FOLDERNAME%\2016\10\02
)
SET /A "X+=1"
GOTO :Looping
)
I would be fine with using a temporary variable for either path, or I could use the concatenated %COPYPATH%\%FOLDERNAME% syntax (which worked when I set this up for a one-off test, but now I want to loop it 50 times). Any advice is much appreciated!
how about...
#echo off
setlocal enabledelayedexpansion
SET "COPYPATH=C:\Dumps"
SET "DESTPATH=D:\NewDumps"
SET "FOLDERNAME[0]=2401010153783FB6"
SET "FOLDERNAME[1]=2401010753BBBBCE"
rem set start to first item index, stop to last
SET/a start=0, stop=1
SET "DAYS=2016\09\28,2016\09\30,2016\10\01"
for /L %%i in (%start%,1,%stop%) do (
echo !FOLDERNAME[%%i]!
set "TEMPVAR=%COPYPATH%\!FOLDERNAME[%%i]!"
set "DESTVAR=%DESTPATH%\!FOLDERNAME[%%i]!"
for %%d in (%DAYS%) do (
rem if it works, remove echo from line below
IF EXIST "!TEMPVAR!\%%d" echo COPY "!TEMPVAR!\%%d" "!DESTPATH!\%%d"
)
)
exit /B
how about
for /L %%a in (0,1,1) do (
for %%b in (2016) do (
for %%c in ("09 28" "09 29" "09 30" "10 01" "10 02") do (
call :sub %%a %%b %%~c
)
)
)
...whatever, etc...
goto :eof
:sub
call set "foldername=%%foldername[%1]%%"
IF EXIST %COPYPATH%\%FOLDERNAME%\%2\%3\%4 (
echo COPY %COPYPATH%\%FOLDERNAME%\%2\%3\%4 %DESTPATH%\%FOLDERNAME%\%2\%3\%4
)
goto :eof
where the echo is there to show you what is proposed, delete that echo keyword to execute.
Note that you offer no explanation of why you switch from tempname to copypath\foldername in your code, so I've assumed it's incomplete substitution.
I suppose all your:
SET TEMPVAR=....
were attempts to save the result of a command into a variable
Well I have to dissapoint you on that ... there is no possibility (yet) to assign directly the result of a command to a veriable in batch ( sorry ). Indirect ways do exist: for /f-loops, use of temporary file, ... but they could make your code more complex
The command you are looking for is
call set tempvar=%%foldername[%x%]%%
The call is used to execute the commands you gave him as parameter inside a batch-file.
So the command will look like (suppose x=0) set tempvar=%foldername[0]% and the call will just execute that (if x=0 off course...).
Good luck!
PS: consider #Magoo's answer to improve your batch script and #elzooilogico if you'd consider to use delayed epansion.
I have this code, but it doesn't seem to be working; I can't work out why:
set dir = %cd%
:char
set dir=%dir:~0,-1%
IF %dir:~-1%=="\" ( goto end ) else ( goto char )
:end
I have narrowed it down to the line
set dir=%dir:~0,-1%
which seems to be setting dir to ~0,-1, but that doesn't make sense because I used the exact same line in another program, and it worked fine.
BTW: This code is meant to be removing the last folder name from the current directory path.
Thanks in advance for any help.
The actual problem in your code is that the variable dir is not assigned in the first line, its name is dir + SPACE. You need to change it to set dir=%cd% or even set "dir=%cd%".
To remove the last folder name from a given path, use a simple for loop and the ~dp expansion (see for /?):
set "FOLDER=%CD%"
for /D %%D in ("%FOLDER%") do (
set "PARENT=%%~dpD"
)
echo Last folder removed: %PARENT%
The is no need to split off character by character and search for \ as you are doing.
Note:
I recommend not to use variable name dir to avoid confusion as there is an equally named internal command.
#ECHO Off
SETLOCAL
set "dir=%cd%"
:char
set dir=%dir:~0,-1%
IF "%dir:~-1%"=="\" ( goto end ) else ( goto char )
:end
SET di
FOR /f %%a IN ("%cd%") DO SET "dir=%%~dpa"
SET di
GOTO :EOF
set recognises Space on each side of the assignment, hence you were assigning the current directory to "dirSpace" and dir was not set at all.
Your if command was missing the quotes around the first argument.
Here's an easier way to do it...
I'm having a few html files where I need to add the pagename as a tag value. Plenty of tools to do mass find and replace, but than you are restricted to a static text, while I need to add the actual filename.
It works perfectly fine on a single file, but if I start to loop into a directory it goes wrong, and I'm not able to figure out where things go wrong.
Doing this on a single predefined file works as expected :
#echo off & setLocal enableDELAYedexpansion
rem Create tmp file to store modified information
set tmpFile=%CD%\test\tmp.txt
set myFile=%CD%\test\test.html
set page=test
rem delete current tmp file
if exist "%tmpFile%" del /f /q "%tmpFile%"
rem find and replace values
set search="container"
set replace="container_!page!"
rem loop through all the lines and replace the string in question
for /F "tokens=*" %%a in (%myFile%) do (
set myLines=%%a
set myLines=!myLines:%search%=%replace%!
echo !myLines! >> %tmpFile%
)
rem update current file with updated content
type !tmpFile! > !myFile!
)
pause
The above nicely finds my string, and replaces it with the one I want (though still static in this case)
But if I want the same logic to loop through more files it goes wrong. This is the code I use :
#echo off & setLocal enableDELAYedexpansion
rem Create tmp file to store modified information
set tmpFile=%CD%\test\tmp.txt
rem switch to test folder
cd %CD%/test
rem Start the loop
For /R %%F in (*.html) do (
rem get page name
set page=%%~nxF
set MyFile=%%F
rem delete current tmp file
if exist "%tmpFile%" del /f /q "%tmpFile%"
rem find and replace values
set search="container"
set replace="container_!page!"
rem loop through all the lines and replace the string in question
for /F "tokens=*" %%a in (%%F) do (
set myLines=%%a
set myLines=!myLines:%search%=%replace%!
echo !myLines! >> %tmpFile%
)
rem update current file with updated content
type !tmpFile! > !myFile!
)
pause
This basically doesn't do anything, I've been trying some otehr variations but these result in either empty pages or pages that contain myLines= as a literal string.
What am I overlooking here ?
[EDITED AREA]
I've managed to get it working partially, but have strange unwanted side effects.
Not using search / replace parameters but using it directly in the replace parts as follows works :
for /F "tokens=*" %%a in (%%F) do (
set myLines=%%a
set "myLines=!myLines:container=container_%%~nF!"
echo !myLines! >> %tmpFile%
)
This replaces container with container_pagename as I wanted , BUT it also removes all esclamation marks on my htm, which is quite annoying, as it ruins all the comments on the page.
so <!-- comment -->
becomes <-- comment -->
Any clue where it goes wrong, or why using parameters doesn't work for me ?
type !inputfile! > !tmpFile!
might be a problem. Suggest you consider what it does...
I'd also change
set var="value"
to
set "var=value"
The first assigns a quoted value to var; the second ensures that stray spces on the line are not included in value assigned to 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.