I have come across some odd behaviour with a batch script recently that I haven't seen before.
Below is what I have had to do to get my script to work. Below is just a piece of the overall script but shows the issue. In short I am having to constantly switch drives in the code. This becomes an issue when using the blat.exe with the attachment on a different drive.
Set DataFile=Test%Date:~-7,2%%Date:~-10,2%.csv
:: Echos the correct name
echo %DataFile%
:: Wouldn't expect to need the two lines below
D:
cd %DATAPATH%
:: If file not present exit
IF NOT EXIST %DataFile% (
echo No File Exists
Exit
)
What I want to be able to do to simplify things (what I would usually do on other environments)
Set DataFile=Test%Date:~-7,2%%Date:~-10,2%.csv
:: Echos the correct name
echo %DataFile%
:: If file not present exit
IF NOT EXIST %DataFile% (
echo No File Exists
Exit
)
Hopefully that makes sense. It seems to be an environment issue or similar, but I cant find anything obvious.
Thank you for any help.
Edit for solution:
As mentioned in a comment below, the underlying issue sent me on a complete wild goose chase and hence the example provided most probably made little to no sense. The problem was a comment inside of the IF statement which I excluded from the examples provided to keep things clean. Turned out the comment was the problem!
The below does not work and complains about a missing ')'
IF NOT EXIST %Filepath%\%FileName% (
echo the file does not exist
:: call {path to an executable}
)
.. Continue script
The script below does work
IF NOT EXIST %Filepath%\%FileName% (
echo the file does not exist
)
:: call {path to an executable}
.. Continue script
Thanks for your help with he issue.
One thing is you are quoting both path1 and file1 when you assign them a value. This will cause a problem when dealing with full paths:
move %path1%%file% %path2%
Expands to (using your values):
move "path1""file1" "path2"
Instead do not quote paths and file name which will be concatenated later, rather quote them when they are combined:
set path1=C:\My Path\
set file1=myfile.txt
set path2="C:\New Path\"
REM Combined path is quoted.
move "%path1%%file%" %path2%
The above expands to:
move "C:\My Path\myfile.txt" "C:\New Path\"
For your full script, try this:
REM Do not quote path/files which are to be combined.
set path1=path1
set file1=file1
set path2="path2"
REM Quote path here since it isn't quoted in the declaration.
IF NOT EXIST "%path1%" (
md "%path1%"
)
REM Combined path is quoted.
move "%path1%%file%" %path2%
::exe below is on another drive
call [path_to_exe].exe
Related
I have a number of files with the same naming scheme. As a sample, four files are called "num_001_001.txt", "num_002_001.txt", "num_002_002.txt", "num_002_003.txt"
The first set of numbers represents which "package" it's from, and the second set of numbers is simply used to distinguish them from one another. So in this example we have one file in package 001, and three files in package 002.
I am writing a windows vista batch command to take all of the files and move them into their own directories, where each directory represents a different package. So I want to move all the files for package 001 into directory "001" and all for 002 into directory "002"
I have successfully written a script that will iterate over all of the txt files and echo them. I have also written a scrip that will move one file into another location, as well as creating the directory if it doesn't exist.
Now I figure that I will need to use substrings, so I used the %var:~start,end% syntax to get them. As a test, I wrote this to verify that I can actually extract the substring and create a directory conditionally
#echo off
set temp=num_001_001.txt
NOT IF exist %temp:~0,7%\
mkdir %temp:~0,7%
And it works. Great.
So then I added the for loop to it.
#echo off
FOR /R %%X IN (*.txt) DO (
set temp=%%~nX
echo directory %temp:~0,7%
)
But this is my output:
directory num_002
directory num_002
directory num_002
directory num_002
What's wrong? Does vista not support re-assigning variables in each iteration?
The four files are in my directory, and one of them should create num_001. I put in different files with 003 004 005 and all of it was the last package's name. I'm guessing something's wrong with how I'm setting things.
I have different workarounds to get the job done but I'm baffled why such a simple concept wouldn't work.
Your problem is that the variable get replaced when the batch processor reads the for command, before it is executed.
Try this:
SET temp=Hello, world!
CALL yourbatchfile.bat
And you'll see Hello printed 5 times.
The solution is delayed expansion; you need to first enable it, and then use !temp! instead of %temp%:
#echo off
SETLOCAL ENABLEDELAYEDEXPANSION
FOR /R %%X IN (*.txt) DO (
set temp=%%~nX
echo directory !temp:~0,7!
)
See here for more details.
Another solution is to move the body of the for loop to a subroutine and call it.
#echo off
FOR /R %%X IN (*.txt) DO call :body %%X
goto :eof
:body
set temp=%~n1
echo directory %temp:~0,7%
goto :eof
Why do this? One reason is that the Windows command processor is greedy about parentheses, and the results may be surprising. I usually run into this when dereferencing variables that contain C:\Program Files (x86).
If the Windows command processor was less greedy, the following code would either print One (1) Two (2) or nothing at all:
#echo off
if "%1" == "yes" (
echo 1 (One)
echo 2 (Two)
)
However, that's not what it does. Either it prints 1 (One 2 (Two), which missing a ), or it prints 2 (Two). The command processor interprets the ) after One as the end of the if statement's body, treats the second echo as if it's outside the if statement, and ignores the final ).
I'm not sure whether this is officially documented, but you can simulate delayed expansion using the call statement:
#echo off
FOR /R %%X IN (*.txt) DO (
set temp=%%~nX
call echo directory %%temp:~0,7%%
)
Doubling the percent signs defers the variable substitution to the second evaluation. However, delayed expansion is much more straightforward.
I am trying to make a batch file that will make a folder on the desktop from user input. Here is my code:
echo What do you want the folder to be called?
SET /p folderName=
md C:\Users\%username%\desktop\%folderName%
However, whenever I try this, It gives me an error saying:
A subdirectory or file C:\Users\Razi\desktop\ already exists.
It doesn't seem to be noticing the %folderName% at the end.
Can somebody tell me what's wrong with my code and give an alternative? Thank you!
Oviously, %folderName% appears to be empty, as you can see in the error message which includes the path argument the md command receives. So md tries to create the already existing directory Desktop.
If the error appears even when you enter a valid directory name, I am pretty sure that the code fragment is part of a block in between parentheses, in which case you need to enable and apply delayed expansion. Otherwise you read the folderName value present before the entire block is executed.
For instance, the following block is seen as a single command line by the command interpreter; %folderName% is expanded (replaced by its value) as soon as the whole line/block is parsed:
(
echo What do you want the folder to be called?
set /P folderName=
md "%USERPROFILE%\desktop\%folderName%"
)
In the following, delayed expansion is enabled (by setlocal); to actually use it, the % expansion has been changed to !; so !folderName! is expanded (read) later, as soon as it is executed:
setlocal EnableDelayedExpansion
rem ...
(
echo What do you want the folder to be called?
set /P folderName=
md "%USERPROFILE%\desktop\!folderName!"
)
rem ...
endlocal
Note that the changed value of folderName is no longer available as soon as endlocal has been executed, or the batch file terminates (where an implicit endlocal happens).
In addition to the above, I put quotation marks around the path at the md command to avoid trouble with white-spaces or special characters, and I changed C:\Users\%USERNAME% to %USERPROFILE% as recommended in Stephan's comment.
I am trying to write a log that a user will create in a batch file, as a small little game, but I can't seem to get the correct directory of the file down. I want to write to this directory:
BatchfileandFolder\subfolder1\subfolder2\ThedataisHere.txt
This is the code I have (I really don't know what I am doing)
Echo Write a piece of text here
set /p UserData=
>>\subfolder1\subfolder2\"ThedataisHere.txt" echo %UserData%
It is essential trying to dig deeper into the directory, but I don't know the exact command, and the help menu for CD, and PATH on the cmd.exe promt don't really help me that much.
Thank you for real human contact, speaking real English
#ECHO OFF
SETLOCAL
SET "logfile=u:\sub folder1\sub folder2\ThedataisHere.txt"
FOR /f "delims=" %%a IN ("%logfile%") DO MD "%%~dpa"
Echo Write a piece of text here
set /p UserData=
>>"%logfile%" echo %UserData%
GOTO :EOF
This method uses a variable logfile so that you aren't forever typing out the name (and avoid the pain if you want to change the names or directories, and the method allows you yo use multiple logfiles easily if you want)
I've deliberately used spaces in directory names to prove the method. The directory gets created immediately after the logfile name is set
append 2>nul to the md instruction line to suppress the directory already exists message
From there, simply use >>"%logfile%" to create the log. The quotes are not required if the filename doesn't contain separators like spaces.
Note that if the first character of the directory specified is \ then the directory is relative to the root, but if it is not then the directory is relative to the current directory on the destination drive. u: is a drive specifier, not a directoryname; I use u: as my test drive. Your choice is up to you.
If the directory structure already exists, it's pretty simple:
#echo off
set /p UserData=Write some text here:
#echo %UserData% >> "subfolder1\subfolder2\TheDataIsHere.txt"
If it doesn't exist already, you have to create it first (tested on Win7 64 bit):
#echo off
if not exist "subfolder1" md "subfolder1"
if not exist "subfolder1\subfolder2" md "subfolder1\subfolder2"
set /p UserData=Write some text here:
#echo %UserData% >> "subfolder1\subfolder2\TheDataIsHere.txt"
Although your description is ample, some important points are missing. It is obvious that you know "How to change the directory that a batch file will output text to", because you use the >> \subfolder\... notation, so this is not your problem. I can only guess that you want to know "How to get the directory where a batch file is located", so you can write to a log file placed two levels below that directory. If this is your problem, then you may use the %~P0 notation, that represent the path of the batch file; that is:
>> "%~P0subfolder1\subfolder2\ThedataisHere.txt" echo %UserData%
Note that the value returned by %~P0 ends in a backslash, so %~P0 must not be separated by an additional backslash from subfolder1; also note that the quotes must enclose the whole path of the file.
If this is not what you want, please carefully describe your real problem. Anyway, try to be clearer in future questions.
I am making a batch file that automatically starts a program, and if the program is not in the original location, it pops up a window, and asks the user to search for the file themselves. this is done with a batch to exe program, and it even includes some advanced commands. the one I used was:
rem browsefolder
you can get the compiler here: http://www.battoexeconverter.com/ anyway, if the user can't find the file, I would like to have an autosearch function available. It would have to chech all directories, and might take a while. I would also need the command to store the location of the file, once it has been found, as a variable. I can't just automatically start it, because I need to kill other processes first, and It would just be alot better to have it as a variable. I have no idea if this is possible, so I'm sorry if this is an outragious request. Once again, I only need the search function. The rest I already have completed.
#echo off
:: the file to look for. (In this case 'myFile.txt')
set filename=myFile.txt
:: the drive or path to search. (In this case searching current drive)
set searchPath=\
:: If the file is found. This variable will be set
set foundFilePath=
:: echos all found paths and returns the last occurrance of the file path
FOR /R "%searchPath%" %%a in (%filename%) DO (
IF EXIST "%%~fa" (
echo "%%~fa"
SET foundFilePath=%%~fa
)
)
IF EXIST "%foundFilePath%" (
echo The foundFilePath var is set to '%foundFilePath%'
) else (
echo Could not find file '%filename%' under '%searchPath%'
)
This will search the current drive for file.exe and set the variable to the location of the last match in the drive.
#echo off
for /r \ %%a in (file.exe) do set "location=%%~dpa"
I have a number of files with the same naming scheme. As a sample, four files are called "num_001_001.txt", "num_002_001.txt", "num_002_002.txt", "num_002_003.txt"
The first set of numbers represents which "package" it's from, and the second set of numbers is simply used to distinguish them from one another. So in this example we have one file in package 001, and three files in package 002.
I am writing a windows vista batch command to take all of the files and move them into their own directories, where each directory represents a different package. So I want to move all the files for package 001 into directory "001" and all for 002 into directory "002"
I have successfully written a script that will iterate over all of the txt files and echo them. I have also written a scrip that will move one file into another location, as well as creating the directory if it doesn't exist.
Now I figure that I will need to use substrings, so I used the %var:~start,end% syntax to get them. As a test, I wrote this to verify that I can actually extract the substring and create a directory conditionally
#echo off
set temp=num_001_001.txt
NOT IF exist %temp:~0,7%\
mkdir %temp:~0,7%
And it works. Great.
So then I added the for loop to it.
#echo off
FOR /R %%X IN (*.txt) DO (
set temp=%%~nX
echo directory %temp:~0,7%
)
But this is my output:
directory num_002
directory num_002
directory num_002
directory num_002
What's wrong? Does vista not support re-assigning variables in each iteration?
The four files are in my directory, and one of them should create num_001. I put in different files with 003 004 005 and all of it was the last package's name. I'm guessing something's wrong with how I'm setting things.
I have different workarounds to get the job done but I'm baffled why such a simple concept wouldn't work.
Your problem is that the variable get replaced when the batch processor reads the for command, before it is executed.
Try this:
SET temp=Hello, world!
CALL yourbatchfile.bat
And you'll see Hello printed 5 times.
The solution is delayed expansion; you need to first enable it, and then use !temp! instead of %temp%:
#echo off
SETLOCAL ENABLEDELAYEDEXPANSION
FOR /R %%X IN (*.txt) DO (
set temp=%%~nX
echo directory !temp:~0,7!
)
See here for more details.
Another solution is to move the body of the for loop to a subroutine and call it.
#echo off
FOR /R %%X IN (*.txt) DO call :body %%X
goto :eof
:body
set temp=%~n1
echo directory %temp:~0,7%
goto :eof
Why do this? One reason is that the Windows command processor is greedy about parentheses, and the results may be surprising. I usually run into this when dereferencing variables that contain C:\Program Files (x86).
If the Windows command processor was less greedy, the following code would either print One (1) Two (2) or nothing at all:
#echo off
if "%1" == "yes" (
echo 1 (One)
echo 2 (Two)
)
However, that's not what it does. Either it prints 1 (One 2 (Two), which missing a ), or it prints 2 (Two). The command processor interprets the ) after One as the end of the if statement's body, treats the second echo as if it's outside the if statement, and ignores the final ).
I'm not sure whether this is officially documented, but you can simulate delayed expansion using the call statement:
#echo off
FOR /R %%X IN (*.txt) DO (
set temp=%%~nX
call echo directory %%temp:~0,7%%
)
Doubling the percent signs defers the variable substitution to the second evaluation. However, delayed expansion is much more straightforward.