Use batch file to check if files with specific extension are in a specific folder - batch-file

In a batch file, I need to get a path from the user, remove the trailing backslash if they included it, and then check if any files with the .sql extension are in the folder that they specified. If not, I want to return them to the variable entry section.
Here's what I have:
REM Get the folder paths from the user
:setfolderpaths
set /p SCRIPTFOLDER="D:\Mark\Centriq Extraction Projects\"
set /p OUTPUTFOLDER="D:\Mark\Centriq Extraction Projects\"
REM View what the user entered (testing only)
echo %SCRIPTFOLDER%
echo %OUTPUTFOLDER%
REM pause here to check the user entry (testing only)
#pause
REM Remove trailing slashes from the folder path if they exist
if %SCRIPTFOLDER:~-1%==\ set SCRIPTFOLDER=%SCRIPTFOLDER:~0,-1%
if %OUTPUTFOLDER:~-1%==\ set OUTPUTFOLDER=%OUTPUTFOLDER:~0,-1%
REM If the folder the user entered doesn't exist, go back to the folder entry section
if not exist %SCRIPTFOLDER% + "\*.sql" (
goto setfolderpaths
)
However, when I run the file, after I press a key to continue at the pause, the cmd window closes immediately. I've checked that the lines removing the backslash work, so the problem seems to be in my if not exist check.
EDIT
Apparently, I had some code in my sample that was confusing what I am trying to figure out. I've added comments to explain what I'm doing in each part. I just need to figure out why my check for.sql files in the user-specified folder isn't working.
UPDATE
Okay, I cleaned up my quoting issues per #LotPings' suggestions.
So, when I put an echo right before the if check:
echo %SCRIPTFOLDER%
#pause
That's displaying a valid path that I know does have sql files in it. So this code isn't working:
if not exist "%SCRIPTFOLDER%\*.sql" (
goto setfolderpaths
)
When I hit a key to continue at the pause the cmd window closes.

This are all quoting issues.
If the double quote is the last char (as is the case above) and you remove it,
the string has only a leading d'quote and still a trailing backslash.
Better quote always like this:
:setfolderpaths
set "SCRIPTFOLDER=D:\Mark\Centriq Extraction Projects\"
set "OUTPUTFOLDER=D:\Mark\Centriq Extraction Projects\"
echo %SCRIPTFOLDER%
echo %OUTPUTFOLDER%
#pause
REM Remove trailing slashes from the folder path if they exist
if "%SCRIPTFOLDER:~-1%"=="\" set "SCRIPTFOLDER=%SCRIPTFOLDER:~0,-1%"
if "%OUTPUTFOLDER:~-1%"=="\" set "OUTPUTFOLDER=%OUTPUTFOLDER:~0,-1%"
if not exist "%SCRIPTFOLDER%\*.sql" (
goto setfolderpaths
)
Also there is no string concatenation with + you used in your if.

Read the answer on Why is no string output with 'echo %var%' after using 'set var = text' on command line? and you know what is wrong on first two SET command lines.
Original question: The folder paths are assigned to the environment variables with both double quotes and so the last character of both environment variable values is " and not the backslash as expected by you.
Edited question: The two folder paths are displayed as prompt text.
The wrong position of first " on SET command lines is responsible for syntax errors on remaining lines as well as + on IF condition line. Windows command processor does not support string concatenations using an operator +. The strings to concatenate must be just written concatenated in the batch file.
Here is a batch file which prompts the user for both paths and runs some checks as the user has the freedom to enter nothing or strings which could do something really bad without appropriate checks in right sequence without using delayed environment variable expansion. The command lines are modified by Windows command processor before execution by each %ScriptFolder% and %OutputFolder% reference. It never really matters what is written in batch file. It matters how each command line or an entire command block looks like after parsing by Windows command processor cmd.exe on execution of batch script.
#echo off
:GetScriptFolderPath
set "ScriptFolder="
set /P "ScriptFolder=Enter script folder path: "
rem Has the user not entered any string?
if not defined ScriptFolder goto GetScriptFolderPath
rem Remove all double quotes from entered string.
set "ScriptFolder=%ScriptFolder:"=%"
rem Has the user entered a string consisting only of double quotes?
if not defined ScriptFolder goto GetScriptFolderPath
rem Remove a backslash at end of user entered string.
if "%ScriptFolder:~-1%" == "\" set "ScriptFolder=%ScriptFolder:~0,-1%"
rem Has the user entered just a backslash (with one or more double quotes)?
if not defined ScriptFolder goto GetScriptFolderPath
rem Is the user entered string really a path to a directory
rem which really exists and contains at least one *.sql file?
if not exist "%ScriptFolder%\*.sql" goto GetScriptFolderPath
:GetOutputFolderPath
set "OutputFolder="
set /P "OutputFolder=Enter output folder path: "
if not defined OutputFolder goto GetOutputFolderPath
set "OutputFolder=%OutputFolder:"=%"
if not defined OutputFolder goto GetOutputFolderPath
if "%OutputFolder:~-1%" == "\" set "OutputFolder=%OutputFolder:~0,-1%"
if not defined OutputFolder goto GetOutputFolderPath
rem Is the user entered string really a path to an existing directory?
if not exist "%OutputFolder%\" goto GetOutputFolderPath
Note: The batch file user can also drag & drop a folder path for example from Windows Explorer into the console window to enter the path and needs to press next only RETURN or ENTER to complete the input prompt.
It is also possible to use set "ScriptFolder=D:\Mark\Centriq Extraction Project" instead of just set "ScriptFolder=" to define a non empty default on which the user has just to press RETURN or ENTER for using it. A default folder path can be also set for the output folder.

Related

How can I copy and rename a file using an environment variable?

I'm working with the command prompt for nearly the first time and am required to create a batch file that prompts the user for a filename with an extension. The bat is supposed to be able to copy and rename said file. The instructor has directed us to use environmental variables to accomplish this task, but I keep getting directory or syntax errors.
I've tried using the variable that the user sets with a previous prompt, but unfortunately this particular instructor hasn't given us practical examples about how to accomplish this particular goal, so I'm flailing. I've tried attaching the variable to the target directory with a generic name for the file. The file and the copy should be in the dame directory.
set /P file_var=Please enter a file name and extension:
copy %file_var% Templatecopy.doc
The file should be copied with the new default name of "Templatecopy.doc" in the target directory.
Churns out syntax and directory errors.
I suggest the following commented code to make this batch file fail-safe as described in answer on How to stop Windows command interpreter from quitting batch file execution on an incorrect user input?
#echo off
:FileNamePrompt
rem Undefine environment variable FileToCopy.
set "FileToCopy="
rem Prompt user for the file name.
set /P "FileToCopy=Please enter a file name and extension: "
rem Has the user not entered anything, prompt the user once more.
if not defined FileToCopy goto FileNamePrompt
rem Remove all double quotes from user input string.
set "FileToCopy=%FileToCopy:"=%"
rem Has the user input just one or more ", prompt the user once more.
if not defined FileToCopy goto FileNamePrompt
rem Check if the user input string really references an existing file.
if not exist "%FileToCopy%" (
echo File "%FileToCopy%" does not exist.
goto FileNamePrompt
)
rem Check if the user input string really references
rem an existing file and not an existing directory.
if exist "%FileToCopy%\" (
echo "%FileToCopy%" references a directory.
goto FileNamePrompt
)
copy /B /Y "%FileToCopy%" "%~dp0Templatecopy.doc" >nul
For understanding the used commands and how they work, open a command prompt window, execute there the following commands, and read entirely all help pages displayed for each command very carefully.
call /? ... explains %~dp0 which is expanding to drive and path of argument 0 which is the batch file path always ending with a backslash.
copy /?
echo /?
goto /?
if /?
rem /?
set /?

how to make batch file handle spaces in file names

I have the following batch file to make git diff invoke spreadsheet compare UI in windows. So I'm trying to pass the git diff's 2nd (old file) and 5th (new file) arguments to spreadsheet compare in order to make it compare the file using git diff.
So now, this batch file only successfully handles files with NO spaces in the file names, it CANNOT handle files with spaces in the file names.
What code should I add to this script to make this batch code handles file with spaces:
#ECHO OFF
set path2=%5
set path2=%path2:/=\%
ECHO %2 > tmp.txt
dir %path2% /B /S >> tmp.txt
C:/"Program Files"/"Microsoft Office"/root/vfs/ProgramFilesX86/"Microsoft Office"/Office16/DCF/SPREADSHEETCOMPARE.EXE tmp.txt
It currently throw errors like this:
Unhandled Exception: System.ArgumentException: Illegal characters in path.
at System.IO.Path.CheckInvalidPathChars(String path, Boolean checkAdditional)
at System.IO.Path.GetFileName(String path)
at ProdianceExcelCompare.Form1.StatusReady()
at ProdianceExcelCompare.Form1.Init()
at ProdianceExcelCompare.Form1..ctor(String instructionFile)
at ProdianceExcelCompare.Program.Main(String[] args)
fatal: external diff died, stopping at London comparison.xlsx
See the following answers on Stack Overflow:
How to set environment variables with spaces?
Why is no string output with 'echo %var%' after using 'set var = text' on command line?
They explain the recommended syntax set "VariableName=variable value" to define an environment variable and the reasons recommending this syntax.
Why does ECHO command print some extra trailing space into the file?
It explains why the space character left to redirection operator > on an ECHO command line is also written into the file as trailing space and how to avoid this safely on variable text written into the file.
See also Microsoft documentation about Using command redirection operators.
On other command lines than ECHO a space left to > is usually no problem.
It is in general wrong to use multiple times " within an argument string like a file or folder path. There should be just one " at beginning and one " at end. This is explained by help of Windows command processor output on last help page on running in a command prompt window cmd /?.
The Microsoft documentation about Naming Files, Paths, and Namespaces explains that the directory separator on Windows is \ and not / and therefore / should not be used in batch files on Windows in file/folder paths.
The help output on running in a command prompt window call /? explains how the arguments of a batch file can be referenced with which modifiers.
The code rewritten according to information posted above and on the referenced pages:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
set "path2=%~5"
set "path2=%path2:/=\%"
>"tmp.txt" echo %2
dir "%path2%" /B /S >>"tmp.txt" 2>nul
"%ProgramFiles%\Microsoft Office\root\vfs\ProgramFilesX86\Microsoft Office\Office16\DCF\SPREADSHEETCOMPARE.EXE" "tmp.txt"
endlocal
The first line in tmp.txt contains the second argument as passed to the batch file, i.e. without or with surrounding double quotes.
The following code is necessary to write the second argument safely always without " into file tmp.txt even on second argument passed to the batch file is "Hello & welcome!":
#echo off
setlocal EnableExtensions DisableDelayedExpansion
set "path2=%~5"
set "path2=%path2:/=\%"
set "Argument2=%~2"
setlocal EnableDelayedExpansion
echo !Argument2!>"tmp.txt"
endlocal
dir "%path2%" /B /S >>"tmp.txt" 2>nul
"%ProgramFiles%\Microsoft Office\root\vfs\ProgramFilesX86\Microsoft Office\Office16\DCF\SPREADSHEETCOMPARE.EXE" "tmp.txt"
endlocal
>tmp.txt echo %~2 cannot be used as not working for something like "Hello & welcome!". Windows command processor would interpret the first string separated by normal space, horizontal tab, comma, equal sign, or no-break space (in OEM code pages) delimited string after & as command or application to execute as described by single line with multiple commands using Windows batch file.
"tmp.txt" could be written everywhere in both batch files also with just tmp.txt. But it is never wrong to enclose the complete file/folder argument string in double quotes even on not being really necessary because of the string does not contain a space or one of these characters &()[]{}^=;!'+,`~. So it is good practice to always enclose a complete file/folder argument string in double quotes. For example running a replace on both batch files searching for tmp.txt and using as replace string %TEMP%\%~n0.tmp would result in using instead of tmp.txt in current directory a temporary file with name of batch file as file name and file extension .tmp in directory for temporary files independent on what is the name of the batch file and what is the path of the directory for temporary files.
The last suggestion is reading this answer for details about the commands SETLOCAL and ENDLOCAL.
The temporary file should be also deleted finally before reaching an exit point for batch file execution.
You can use quotes as below:
It treats the string in quotes as a title of the new command window. So, you may do the following:
start "" "yourpath"
Found it in the below link :
https://ccm.net/forum/affich-16973-open-a-file-with-spaces-from-batch-file

%~1 and %1 Automatically Removing Everything after the first Space

So I am creating a batch file to store a selected folder's path into a text file to refer to it later on using another batch script...
I created registry entries to include a right-click context menu for any folder which triggers this specific batch file.
Basically When you right click a folder and click "Send to Script" it is supposed to copy the whole path / location of the right clicked folder.
To do so I am using the following command:
SET TargetDir=%~1
I also tried using %1and I also tried using the following code with delimiters
FOR /f "delims=;" %%a in ("%~1") do (
#echo %%a
)
The problem is that CMD is automatically trimming everything after the first space and since this is a path I am copying, I want to keep all the spaces and the path as is
Ex. If I use the command on a Folder such as "C:/folder/subfolder" the copyng is done correctly But If I use the command on a Folder such as "C:/folder/sub folder" the copying is done incorrectly and will only give me "C:/folder/sub" removing all the rest found after the first space detected.
Registry Entries
[HKEY_CLASSES_ROOT\Directory\shell\send-to-script]
"MUIVerb"="Send To Script"
"SubCommands"="sendscript"
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\CommandStore\shell\sendscript]
#="Send To Script"
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\CommandStore\shell\sendscript\command]
#="C:\\scripts\\pathtotext.bat %1"
Thanks for your help
You should change your registry key [...\sendscript\command] to
#="C:\\temp\\blob.bat \"%1\""
And in your batch you should use
REM The DisableDelayedExpansion is for preserve "!" in path names
setlocal DisableDelayedExpansion
SET "TargetDir=%~1"
setlocal EnableDelayedExpansion
(
echo target is !TargetDir!
) > C:\scripts\target.log
if "reseverdFolder" == "!TargetDir!" echo This folder is reserved
The batch file is not correct registered. For example look with regedit on value of registry key:
HKEY_CLASSES_ROOT\rtffile\shell\open\command
The value is displayed as:
"%ProgramFiles%\Windows NT\Accessories\WORDPAD.EXE" "%1"
So there are two arguments which are both enclosed in double quotes:
Argument 0 is the application to run with full path, file name and file extension enclosed in double quotes as path contains a space character.
Argument 1 is the name of the RTF file referenced with %1 passed by Windows Explorer with full path, file name and file extension which of course can also contain a space or any of the characters &()[]{}^=;!'+,`~ which require also enclosing entire argument in double quotes as output by cmd.exe on running it in a command prompt window with cmd /? on last help page.
So you need in your *.reg file used to import into Windows registry:
#="\"C:\\scripts\\pathtotext.bat\" \"%1\""
This string value is displayed in registry editor as:
"C:\scripts\pathtotext.bat" "%1"
And then you can use %1 or %~1 in your batch file as explained by help of command CALL output on running in a command prompt window on execution of call /?.
SET "TargetDir=%*"
Since the parameter apparently being supplied is C:\folder\sub folder then %~1 selects only the first supplied parameter of what cmd sees as two parameters.
%* means "the whole tail"
and echoing %* should show you exactly what cmd is seeing.

Stripping part of a filename and using it for a comparison

I'm building a script for Windows command line in which I try to check some filenames in a FOR loop, and then stripping off part of the filename into a variable for further use. Basically, what I want to happen is this:
List all files in a certain directory, splitting of the extension like .osm.pbf in this case.
Assign the filename to a variable.
Out the last 7 characters of the filename in another variable.
Compare this new variable to "-latest".
If the compare is true, cut a part of the variable containing the filename.
If the compare is false, take over the complete variable into another variable.
Through some trial and error and some searching online, I've arrived at this point (which still isn't doing what I want):
FOR /F "tokens=1-2 delims=." %%M IN ('DIR /b %VECTOR_WORKDIR%\*.osm.pbf') DO (
SET VECTOR_CURRENT_MAP2=%%M
ECHO !VECTOR_CURRENT_MAP2! >> %VECTOR_LOGFILE%
SET LAST_BIT_TEMP=!VECTOR_CURRENT_MAP2:~-7!
ECHO !LAST_BIT_TEMP! >> %VECTOR_LOGFILE%
SET LAST_BIT=!LAST_BIT_TEMP: =!
ECHO !LAST_BIT! >> %VECTOR_LOGFILE%
IF !LAST_BIT!=="-latest" (
SET VECTOR_CURRENT_MAP3=!VECTOR_CURRENT_MAP2:~0,-8!
ELSE
SET VECTOR_CURRENT_MAP3=!VECTOR_CURRENT_MAP2!
)
ECHO !VECTOR_CURRENT_MAP3! >> %VECTOR_LOGFILE%
)
This results in these lines in the log file, for the file basse-normandie-latest.osm.pbf:
basse-normandie-latest
-latest
-latest
ECHO is on.
The first echo is correct, although the filename has a trailing space. (So actually it's "basse-normandie-latest ".)
The second echo doesn't seem to take this training space into account, as it correctly gives "-latest" as the last 7 characters. This echo also has a trailing space (So actually it's "-latest ".)
The third echo is an attempt to clear the spaces from the variable (by using ": ="), but this results in another trailing space. (So actually it's "latest ".)
The final echo after the IF statement (where I try to cut the "-latest" part from the filename), results in "ECHO is on".
I have SETLOCAL enabledelayedexpansion enableextensions declared at the top of my script.
Any thoughts on how to make this work, i.e. get rid of the trailing spaces to make the comparison work?
Thanks in advance for any pointers in the right direction!
A line like
ECHO !VECTOR_CURRENT_MAP2! >> %VECTOR_LOGFILE%
results in appending the value of the environment variable VECTOR_CURRENT_MAP2 to file with file name stored in environment variable VECTOR_LOGFILE with a trailing space because there is a space before redirection operator >> which is interpreted by Windows command processor as part of the string to output by command ECHO. This space must be removed to get the file name redirected into the log file without a trailing space.
In general it is critical on redirecting a variable string into a file without a space between the variable string and the redirection operator in case of the variable string ends with a space and a number being a valid handle number like  1 or  2 or  3. There are several solutions to workaround this problem like specifying the redirection left to command ECHO, i.e.
>>%VECTOR_LOGFILE% ECHO !VECTOR_CURRENT_MAP2!
But on using delayed expansion as simply necessary here, it is safe to append the redirection at end without a space between exclamation mark and >>, i.e.
ECHO !VECTOR_CURRENT_MAP2!>> %VECTOR_LOGFILE%
The space after redirection operator is ignored by Windows command processor and therefore can be kept although many batch file programmers (like me) with good syntax highlighting don't insert a space after a redirection operator.
On comparing strings with command IF and enclosing one string in double quotes which is always a good idea, it must be made sure that the other string is also enclosed in double quotes. The command IF does not remove the double quotes before comparing the strings. The double quotes are parts of the compared strings.
The condition
IF !LAST_BIT!=="-latest"
is only true if the string assigned to environment variable LAST_BIT would be with surrounding quotes which is never the case with your batch code and therefore the condition is never true.
Correct would be:
IF "!LAST_BIT!"=="-latest"
There is no need to use command DIR to search for files with a pattern in a directory as command FOR is designed for doing exactly this task. Processing of output of command DIR is an extension of FOR available only if command extensions are enabled as by default.
The file extension is defined by Microsoft as everything after last dot in name of a file. Therefore the file extension for your files is pbf respectively .pbf and .osm belongs to the file name.
Command FOR offers several modifiers to get specific parts of a file or directory name. Those modifiers are explained in help output into console window on running in a command prompt window for /?. Help of command CALL output with call /? explains the same for processing parameters of a batch file or subroutine (batch file embedded within a batch file).
Your code with all mistakes removed:
FOR %%M IN (*.osm.pbf) DO (
SET "VECTOR_CURRENT_MAP2=%%~nM"
SET "VECTOR_CURRENT_MAP2=!VECTOR_CURRENT_MAP2:~0,-4!"
ECHO !VECTOR_CURRENT_MAP2!>>%VECTOR_LOGFILE%
SET "LAST7CHARS=!VECTOR_CURRENT_MAP2:~-7!"
ECHO !LAST7CHARS!>>%VECTOR_LOGFILE%
IF "!LAST7CHARS!" == "-latest" (
SET "VECTOR_CURRENT_MAP3=!VECTOR_CURRENT_MAP2:~0,-7!"
) ELSE (
SET "VECTOR_CURRENT_MAP3=!VECTOR_CURRENT_MAP2!"
)
ECHO !VECTOR_CURRENT_MAP3!>>%VECTOR_LOGFILE%
)
Easier would be using this code with using string substitution feature of command SET, i.e. search within a string case-insensitive for all occurrences of a string and replace them with another string which can be also an empty string.
FOR %%M IN (*.osm.pbf) DO (
SET "VECTOR_CURRENT_MAP2=%%~nM"
SET "VECTOR_CURRENT_MAP2=!VECTOR_CURRENT_MAP2:~0,-4!"
ECHO !VECTOR_CURRENT_MAP2!>>%VECTOR_LOGFILE%
SET "VECTOR_CURRENT_MAP3=!VECTOR_CURRENT_MAP2:-latest=!"
ECHO !VECTOR_CURRENT_MAP3!>>%VECTOR_LOGFILE%
)
%%~nM is replaced on execution by Windows command processor by the name of the file without drive, path and file extension resulting for your example in basse-normandie-latest.osm.
The unwanted file name part .osm is removed with the next line in both batch code blocks which chops the last 4 characters from the file name string.
For understanding the used commands and how they work, open a command prompt window, execute there the following commands, and read entirely all help pages displayed for each command very carefully.
echo /?
for /?
if /?
set /?
Read the answer on question Why is no string output with 'echo %var%' after using 'set var = text' on command line? for an explanation why I used set "variable=value" on every line which assigns a value string to an environment variable because trailing whitespaces are critical for your task.

Create Folder on desktop using user input in Batch File

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.

Resources