- How to substitute variable contents in a Windows batch file
- 7 Answers 7
- How to test if a file is a directory in a batch script?
- 22 Answers 22
- The NUL technique seems to only work on 8.3 compliant file names.
- (In other words, `D:\Documents and Settings` is «bad» and `D:\DOCUME
- Windows batch file file download from a URL
- 20 Answers 20
- Downloading files in PURE BATCH. Without any JScript, VBScript, Powershell, etc. Only pure Batch!
- /* steve jansen */
- // another day in paradise hacking code and more
- Windows Batch Scripting: Variables
- Variable Declaration
- Variable Assignment
- Reading the Value of a Variable
- Listing Existing Variables
- Variable Scope (Global vs Local)
- Special Variables
- Command Line Arguments to Your Script
- Tricks with Command Line Arguments
- Some Final Polish
- Comments
- Guides
- Recent Posts
- Social Stuff
How to substitute variable contents in a Windows batch file
I’m writing a simple script to substitute text in an environment variable with other text. The trouble I get is with the substituted or substituted text being pulled from other variables
Works fine (output is ‘The fat cat’ and ‘The thin cat’
However, if ‘fat’ or ‘thin’ are in variables, it doesn’t work
I know this can be done as I’ve seen it in blogs before, but I never saved the link to the blogs.
Anyone have any ideas?
PS. I’m running the scripts on Windows 7
PPS. I know this is easier in Perl/Python/other script language of choice, but I just want to know why something that should be easy is not immediately obvious.
PPPS. I’ve also tried the scripts with delayed expansion explicitly turned on
This makes no difference.
7 Answers 7
Please try the following:
Copy and paste the code into Notepad and save it as a batch file.
I hope you’re convinced!
Use CALL. Put the following in a batch script and run it:
As stated here, we use the fact that:
internal_cmd Run an internal command, first expanding any variables in the argument.
In our case internal_cmd is initially set a=%%a:%b%^=%c%%%.
After expansion internal_cmd becomes set a=%a:fat=thin%.
Thus, in our case running
is equivalent to running:
The problem with:
is that it tries to expand two variables: a: and =thin with a c constant string between them.
The first command outputs:
which is piped into a second command shell for evaluation.
And. How about this?
Recently I came accross the same situation..As said earlier, I used like below and worked.
I try to avoid using SETLOCAL enabledelayedexpansion . ENDLOCAL all (or nearly all) the time, because usually I want to set or modify a few variables and I want the new values to be available in other areas of the script or after the batch script ends (SETLOCAL|ENDLOCAL will forget about any new variables or changes to variables in the «SETLOCAL» part of the script. Sometimes that’s handy, but for me I find it’s usually not.
Currently I use the method described by @Zuzel, but before I knew about that method, I used to use this, which is very similar (but looks a bit more complicated):
the output from running the script:
I like this method because you can call external programs (or internal commands) using modified variables and also capture and process the output of the command (line by line).
But, Zuzel’s method is simpler and cleaner for most situations, including the one you described.
Note:
Both of these methods (and also SETLOCAL enabledelayedexpansion . ENDLOCAL , of course), only work correctly if run from within a batch script. If you try to use either of these two methods («call» or «for») directly in a command prompt window, you will get something different from what the output was running from a script.
For example, run this as a script:
the output from running the script:
Now, run those commands directly in a command prompt window:
examine the before and after output lines from the command prompt window:
Notice that the substitutions are made correctly, but also notice that with running these commands directly in the command prompt window, it adds a set of «%» (percent signs) before and after the expected value each time the substitution is made. So, it makes it difficult to test any of these methods directly in the command prompt window.
How to test if a file is a directory in a batch script?
Is there any way to find out if a file is a directory?
I have the file name in a variable. In Perl I can do this:
22 Answers 22
You can do it like so:
However, this only works for directories without spaces in their names. When you add quotes round the variable to handle the spaces it will stop working. To handle directories with spaces, convert the filename to short 8.3 format as follows:
si converts %%i to an 8.3 filename. To see all the other tricks you can perform with FOR variables enter HELP FOR at a command prompt.
(Note — the example given above is in the format to work in a batch file. To get it work on the command line, replace the %% with % in both places.)
1\» echo It’s a directory – MarioVilas Jun 6 ’13 at 14:08
si* ECHO IS FOLDER – Jakob Sternberg Jan 3 ’14 at 4:16
Works with directory names that contains spaces:
Note that the quotes are necessary if the directory contains spaces:
Can also be expressed as:
This is safe to try at home, kids!
1\» echo It’s a directory – MarioVilas Jun 6 ’13 at 14:10
Recently failed with different approaches from the above. Quite sure they worked in the past, maybe related to dfs here. Now using the files attributes and cut first char
f1 . It expands paths like . and .. to real path. – WesternGun Feb 8 at 22:59
Further to my previous offering, I find this also works:
No quotes around %1 are needed because the caller will supply them. This saves one entire keystroke over my answer of a year ago 😉
Here’s a script that uses FOR to build a fully qualified path, and then pushd to test whether the path is a directory. Notice how it works for paths with spaces, as well as network paths.
Sample output with the above saved as «isdir.bat»:
This works perfectly
1 to remove quotes from %1, and add a backslash at end. Then put thw whole into qutes again.
A variation of @batchman61’s approach (checking the Directory attribute).
This time I use an external ‘find’ command.
(Oh, and note the && trick. This is to avoid the long boring IF ERRORLEVEL syntax.)
- Directories.
- Directory symbolic links or junctions.
- Broken directory symbolic links or junctions. (Doesn’t try to resolve links.)
- Directories which you have no read permission on (e.g. «C:\System Volume Information»)
The NUL technique seems to only work on 8.3 compliant file names.
(In other words, `D:\Documents and Settings` is «bad» and `D:\DOCUME
I think there is some difficulty using the «NUL» tecnique when there are SPACES in the directory name, such as «Documents and Settings.»
I am using Windows XP service pack 2 and launching the cmd prompt from %SystemRoot%\system32\cmd.exe
Here are some examples of what DID NOT work and what DOES WORK for me:
(These are all demonstrations done «live» at an interactive prompt. I figure that you should get things to work there before trying to debug them in a script.)
This DID NOT work:
D:\Documents and Settings>if exist «D:\Documents and Settings\NUL» echo yes
This DID NOT work:
D:\Documents and Settings>if exist D:\Documents and Settings\NUL echo yes
This DOES work (for me):
D:\Documents and Settings>cd ..
D:\>REM get the short 8.3 name for the file
Volume in drive D has no label. Volume Serial Number is 34BE-F9C9
Directory of D:\
09/25/2008 05:09 PM 2008
09/25/2008 05:14 PM 200809
1.25 2008.09.25
09/23/2008 03:44 PM BOOST_
3 boost_repo_working_copy
09/02/2008 02:13 PM 486,128 CHROME
1.EXE ChromeSetup.exe
02/14/2008 12:32 PM cygwin
[[Look right here . ]]
09/25/2008 08:34 AM DOCUME
1 Documents and Settings
09/11/2008 01:57 PM 0 EMPTY_
1.TXT empty_testcopy_file.txt
01/21/2008 06:58 PM NATION
1 National Instruments Downloads
10/12/2007 11:25 AM NVIDIA
05/13/2008 09:42 AM Office10
09/19/2008 11:08 AM PROGRA
1 Program Files
12/02/1999 02:54 PM 24,576 setx.exe
09/15/2008 11:19 AM TEMP
02/14/2008 12:26 PM tmp
01/21/2008 07:05 PM VXIPNP
09/23/2008 12:15 PM WINDOWS
02/21/2008 03:49 PM wx28
02/29/2008 01:47 PM WXWIDG
2 wxWidgets
3 File(s) 510,704 bytes
20 Dir(s) 238,250,901,504 bytes free
D:\>REM now use the \NUL test with the 8.3 name
D:\>if exist d:\docume
This works, but it’s sort of silly, because the dot already implies i am in a directory:
D:\Documents and Settings>if exist .\NUL echo yes
Windows batch file file download from a URL
I am trying to download a file from a website (ex. http://www.example.com/package.zip) using a Windows batch file. I am getting an error code when I write the function below:
The batch file doesn’t seem to like the «/» after the http. Are there any ways to escape those characters so it doesn’t assume they are function parameters?
20 Answers 20
With PowerShell 2.0 (Windows 7 preinstalled) you can use:
Starting with PowerShell 3.0 (Windows 8 preinstalled) you can use Invoke-WebRequest :
From a batch file they are called:
(PowerShell 2.0 is available for installation on XP, 3.0 for Windows 7)
There’s a standard Windows component which can achieve what you’re trying to do: BITS. It has been included in Windows since XP and 2000 SP3.
The job name is simply the display name for the download job — set it to something that describes what you’re doing.
This might be a little off topic, but you can pretty easily download a file using Powershell. Powershell comes with modern versions of Windows so you don’t have to install any extra stuff on the computer. I learned how to do it by reading this page:
Last I checked, there isn’t a command line command to connect to a URL from the MS command line. Try wget for Windows:
http://gnuwin32.sourceforge.net/packages/wget.htm
In Linux, you can use «wget».
Alternatively, you can try VBScript. They are like command line programs, but they are scripts interpreted by the wscript.exe scripts host. Here is an example of downloading a file using VBS:
https://serverfault.com/questions/29707/download-file-from-vbscript
Downloading files in PURE BATCH. Without any JScript, VBScript, Powershell, etc. Only pure Batch!
Some people are saying it’s not possible of downloading files with a batch script without using any JScript or VBScript, etc. But they are definitely wrong!
Here is a simple method that seems to work pretty well for downloading files in your batch scripts. It should be working on almost any file’s URL. It is even possible to use a proxy server if you need it.
For downloading files, we can use BITSADMIN.EXE from the Windows system. There is no need for downloading/installing anything or using any JScript or VBScript, etc. Bitsadmin.exe is present on most Windows versions, probably from XP to Windows 10.
USAGE:
You can use the BITSADMIN command directly, like this:
bitsadmin /transfer mydownloadjob /download /priority FOREGROUND «http://example.com/File.zip» «C:\Downloads\File.zip»
Proxy Server:
For connecting using a proxy, use this command before downloading.
bitsadmin /setproxysettings mydownloadjob OVERRIDE «proxy-server.com:8080»
Click this LINK if you want more info about BITSadmin.exe
TROUBLESHOOTING:
If you get this error: «Unable to connect to BITS — 0x80070422»
Make sure the windows service «Background Intelligent Transfer Service (BITS)» is enabled and try again. (It should be enabled by default.)
CUSTOM FUNCTIONS
Call :DOWNLOAD_FILE «URL»
Call :DOWNLOAD_PROXY_ON «SERVER:PORT»
Call :DOWNLOAD_PROXY_OFF
I made these 3 functions for simplifying the bitsadmin commands. It’s easier to use and remember. It can be particularly useful if you are using it multiple times in your scripts.
PLEASE NOTE.
Before using these functions, you will first need to copy them from CUSTOM_FUNCTIONS.CMD to the end of your script. There is also a complete example: DOWNLOAD-EXAMPLE.CMD
:DOWNLOAD_FILE «URL»
The main function, will download files from URL.
:DOWNLOAD_PROXY_ON «SERVER:PORT»
(Optional) You can use this function if you need to use a proxy server.
Calling the :DOWNLOAD_PROXY_OFF function will disable the proxy server.
/* steve jansen */
// another day in paradise hacking code and more
Windows Batch Scripting: Variables
Today we’ll cover variables, which are going to be necessary in any non-trivial batch programs. The syntax for variables can be a bit odd, so it will help to be able to understand a variable and how it’s being used.
Variable Declaration
DOS does not require declaration of variables. The value of undeclared/uninitialized variables is an empty string, or «» . Most people like this, as it reduces the amount of code to write. Personally, I’d like the option to require a variable is declared before it’s used, as this catches silly bugs like typos in variable names.
Variable Assignment
The SET command assigns a value to a variable.
NOTE: Do not use whitespace between the name and value; SET foo = bar will not work but SET foo=bar will work.
The /A switch supports arthimetic operations during assigments. This is a useful tool if you need to validated that user input is a numerical value.
A common convention is to use lowercase names for your script’s variables. System-wide variables, known as environmental variables, use uppercase names. These environmental describe where to find certain things in your system, such as %TEMP% which is path for temporary files. DOS is case insensitive, so this convention isn’t enforced but it’s a good idea to make your script’s easier to read and troubleshoot.
WARNING: SET will always overwrite (clobber) any existing variables. It’s a good idea to verify you aren’t overwriting a system-wide variable when writing a script. A quick ECHO %foo% will confirm that the variable foo isn’t an existing variable. For example, it might be tempting to name a variable “temp”, but, that would change the meaning of the widely used “%TEMP%” environmental varible. DOS includes some “dynamic” environmental variables that behave more like commands. These dynamic varibles include %DATE% , %RANDOM% , and %CD% . It would be a bad idea to overwrite these dynamic variables.
Reading the Value of a Variable
In most situations you can read the value of a variable by prefixing and postfixing the variable name with the % operator. The example below prints the current value of the variable foo to the console output.
There are some special situations in which variables do not use this % syntax. We’ll discuss these special cases later in this series.
Listing Existing Variables
The SET command with no arguments will list all variables for the current command prompt session. Most of these varaiables will be system-wide environmental variables, like %PATH% or %TEMP% .
NOTE: Calling SET will list all regular (static) variables for the current session. This listing excludes the dynamic environmental variables like %DATE% or %CD% . You can list these dynamic variables by viewing the end of the help text for SET, invoked by calling SET /?
Variable Scope (Global vs Local)
By default, variables are global to your entire command prompt session. Call the SETLOCAL command to make variables local to the scope of your script. After calling SETLOCAL , any variable assignments revert upon calling ENDLOCAL , calling EXIT , or when execution reaches the end of file (EOF) in your script.
This example demonstrates changing an existing variable named foo within a script named HelloWorld.cmd . The shell restores the original value of %foo% when HelloWorld.cmd exits.
A real life example might be a script that modifies the system-wide %PATH% environmental variable, which is the list of directories to search for a command when executing a command.
Special Variables
There are a few special situations where variables work a bit differently. The arguments passed on the command line to your script are also variables, but, don’t use the %var% syntax. Rather, you read each argument using a single % with a digit 0-9, representing the ordinal position of the argument. You’ll see this same style used later with a hack to create functions/subroutines in batch scripts.
There is also a variable syntax using ! , like !var! . This is a special type of situation called delayed expansion. You’ll learn more about delayed expansion in when we discuss conditionals (if/then) and looping.
Command Line Arguments to Your Script
You can read the command line arguments passed to your script using a special syntax. The syntax is a single % character followed by the ordinal position of the argument from 0 – 9 . The zero ordinal argument is the name of the batch file itself. So the variable %0 in our script HelloWorld.cmd will be “HelloWorld.cmd”.
The command line argument variables are * %0 : the name of the script/program as called on the command line; always a non-empty value * %1 : the first command line argument; empty if no arguments were provided * %2 : the second command line argument; empty if a second argument wasn’t provided * …: * %9 : the ninth command line argument
NOTE: DOS does support more than 9 command line arguments, however, you cannot directly read the 10th argument of higher. This is because the special variable syntax doesn’t recognize %10 or higher. In fact, the shell reads %10 as postfix the %0 command line argument with the string “0”. Use the SHIFT command to pop the first argument from the list of arguments, which “shifts” all arguments one place to the left. For example, the the second argument shifts from position %2 to %1 , which then exposes the 10th argument as %9 . You will learn how to process a large number of arguments in a loop later in this series.
Tricks with Command Line Arguments
Command Line Arguments also support some really useful optional syntax to run quasi-macros on command line arguments that are file paths. These macros are called variable substitution support and can resolve the path, timestamp, or size of file that is a command line argument. The documentation for this super useful feature is a bit hard to find – run ‘FOR /?’ and page to the end of the output.
I removes quotes from the first command line argument, which is super useful when working with arguments to file paths. You will need to quote any file paths, but, quoting a file path twice will cause a file not found error.
fI is the full path to the folder of the first command line argument
fsI is the same as above but the extra s option yields the DOS 8.3 short name path to the first command line argument (e.g., C:\PROGRA
1 is usually the 8.3 short name variant of C:\Program Files ). This can be helpful when using third party scripts or programs that don’t handle spaces in file paths.
dpI is the full path to the parent folder of the first command line argument. I use this trick in nearly every batch file I write to determine where the script file itself lives. The syntax SET parent=%
dp0 will put the path of the folder for the script file in the variable %parent% .
nxI is just the file name and file extension of the first command line argument. I also use this trick frequently to determine the name of the script at runtime. If I need to print messages to the user, I like to prefix the message with the script’s name, like ECHO %
n0: some message instead of ECHO some message . The prefixing helps the end user by knowing the output is from the script and not another program being called by the script. It may sound silly until you spend hours trying to track down an obtuse error message generated by a script. This is a nice piece of polish I picked up from the Unix/Linux world.
Some Final Polish
I always include these commands at the top of my batch scripts:
The SETLOCAL command ensures that I don’t clobber any existing variables after my script exits. The ENABLEEXTENSIONS argument turns on a very helpful feature called command processor extensions. Trust me, you want command processor extensions. I also store the name of the script (without the file extension) in a variable named %me% ; I use this variable as the prefix to any printed messages (e.g. ECHO %me%: some message ). I also store the parent path to the script in a variable named %parent% . I use this variable to make fully qualified filepaths to any other files in the same directory as our script.
Posted by Steve Jansen Mar 1 st , 2013 batch, scripting, shell, windows
Comments
Hi, I’m Steve. I’m a software developer loving life in Charlotte, NC, an (ISC) 2 CSSLP and an avid fan of Crossfit.
And, no, I’m not Steve Jansen the British jazz drummer, though that does sound like a sweet career.
Guides
Recent Posts
Social Stuff
- @steve-jansen on GitHub
- @steve-jansen on StackOverflow
- @steve-jansen ProTips on Coderwall
- @steve-jansen on Microsft Connect
- @steve-jansen on ASP.NET User Voice
- Subscribe via RSS
Copyright © 2015 — Steve Jansen — Powered by Octopress