Getting Started with Windows Batch Scripting
Windows batch scripting is incredibly accessible – it works on just about any modern Windows machine. You can
create and modify batch scripts on just about any modern Windows machine. The tools come out of the box: the
Windows command prompt and a text editor like Notepad.exe. It’s definitely far from the best shell scripting langauge,
but, it gets the job done. It’s my “duct tape” for Windows.
Launching the Command Prompt
Windows gurus launch the command prompt using the keyboard shortcut Windows Logo Key+R (i.e., “Run”) >
Type cmd.exe then Enter. This is way faster than navigating the Windows Start Menu to find the Command
Prompt.
Editing Batch Files
The universal text editor for batch files is Notepad (Windows Logo Key + R > Type notepad then Enter). Since
batch files are just ASCII text, you can probably use just about any text editor or word processor. Very few editors do
anything special for Batch files like syntax highlighting or keyword support, so notepad is good enough fine and will
likely be installed on just about every Windows system you encounter.
Viewing Batch Files
I would stick with Notepad for viewing the contents of a batch file. In Windows Explorer (aka, “My Computer”), you
should be able to view a batch file in Notepad by right clicking the file and seleting Edit from the context menu. If you
need to view the contents within a command prompt window itself, you can use a DOS command like TYPE
myscript.cmd or MORE myscript.cmd or EDIT myscript.cmd
Batch File Names and File Extensions
Assuming you are using Windows XP or newer, I recommend saving your batch files with the file extension .cmd.
Some seriously outdated Windows versions used .bat, though I recommend sticking with the more
modern .cmdto avoid some rare side effects with .bat files.
With the .cmd file extension, you can use just about filename you like. I recommend avoiding spaces in filenames, as
spaces only create headaches in shell scripting. Pascal casing your filenames is an easy way to avoid spaces
(e.g., HelloWorld.cmd instead of Hello World.cmd). You can also use punctuation characters like . or -
or _ (e.g. Hello.World.cmd, Hello-World.cmd, Hello_World.cmd).
Another thing with names to consider is avoiding names that use the same name of any built-in commands, system
binaries, or popular programs. For example, I would avoid naming a script ping.cmd since there is a widely used
system binary named ping.exe. Things might get very confusing if you try to run ping and inadvertently
call ping.cmd when you really wanted ping.cmd. (Stay tuned for how this could happen.) I might called the
script RemoteHeartbeat.cmd or something similar to add some context to the script’s name and also avoid any
naming collisions with any other executable files. Of course, there could be a very unique circumstance in which you
want to modify the default behavior of ping in which this naming suggestion would not apply.
Saving Batch Files in Windows
Notepad by default tries to save all files as plain jane text files. To get Notepad to save a file with a .cmd extension, you
will need to change the “Save as type” to “All Files (.)”. See the screenshot below for an example of saving a script
named “HelloWorld.cmd” in Notepad.
SIDEBAR: I’ve used a shortcut in this screenshot that you will learn more about later. I’ve saved the file to my “user profile
folder” by naming the file %USERPROFILE%\HelloWorld.cmd . The %USERPROFILE% keyword is the Windows
environmental variable for the full path to your user profile folder. On newer Windows systems, your user profile folder will
typically be C:\Users\<your username> . This shortcut saves a little bit of time because a new command prompt will
generally default the “working directory” to your user profile folder. This lets you run HelloWorld.cmd in a new command
prompt without changing directories beforehand or needing to specify the path to the script.
Running your Batch File
The easy way to run your batch file in Windows is to just double click the batch file in Windows Explorer (aka “My
Computer”). Unfortunately, the command prompt will not give you much of a chance to see the output and any errors.
The command prompt window for the script will disappear as soon as the script exits. (We will learn how to handle
this problem in Part 10 – Advanced Tricks ).
When editing a new script, you will likely need to run the batch file in an existing command window. For newbies, I
think the easiest foolproof way to run your script is to drag and drop the script into a command prompt window. The
command prompt will enter the full path to your script on the command line, and will quote any paths containing
spaces.
Some other tips to running batch files:
You can recall previous commands using the up arrow and down arrow keys to navigate the command line history.
I usually run the script as %COMPSPEC% /C /D "C:\Users\User\SomeScriptPath.cmd" Arg1 Arg2 Arg3 This
runs your script in a new command prompt child process. The /C option instructs the child process to quit when your script quits.
The /D disables any auto-run scripts (this is optional, but, I use auto-run scripts). The reason I do this is to keep the command
prompt window from automatically closing should my script, or a called script, call the EXITcommand. The EXIT command
automatically closes the command prompt window unless the EXIT is called from a child command prompt process. This is
annoying because you lose any messages printed by your script.
Comments
The official way to add a comment to a batch file is with the REM (Remark) keyword:
REM This is a comment!
The power user method is to use ::, which is a hack to uses the the label operator : twice, which is almost always
ignored.
Most power authors find the :: to be less distracting than REM. Be warned though there are a few places where ::will
cause errors.
:: This is a comment too!! (usually!)
For example, a FOR loop will error out with :: style comments. Simply fall back to using REM if you think you have a
situation like this.
Silencing Display of Commands in Batch Files
The first non-comment line of a batch file is usually a command to turn off printing (ECHO’ing) of each batch file line.
@ECHO OFF
The @ is a special operator to suppress printing of the command line. Once we set ECHO’ing to off, we won’t need
the @ operator again in our script commands.
You restore printing of commands in your script with:
ECHO ON
Upon exit of your script, the command prompt will automatically restore ECHO to it’s previous state.
Debugging Your Scripts
Batch files invole a lot of trial and error coding. Sadly, I don’t know of any true debugger for Windows batch scripts.
Worse yet, I don’t know of a way to put the command processor into a verbose state to help troubleshoot the script
(this is the common technique for Unix/Linux scripts.) Printing custom ad-hoc debugging messages is about your only
option using the ECHO command. Advanced script writers can do some trickery to selectively print debugging
messages, though, I prefer to remove the debugging/instrumentation code once my script is functioning as desired.
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.
SET foo=bar
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.
SET /A four=2+2
4
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.
C:\> SET foo=bar
C:\> ECHO %foo%
bar
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.
%~1 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.
SET myvar=%~1
%~f1 is the full path to the folder of the first command line argument
%~fs1 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.
%~dp1 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%.
%~nx1 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:
SETLOCAL ENABLEEXTENSIONS
SET me=%~n0
SET parent=%~dp0
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.
Return Code Conventions
By convention, command line execution should return zero when execution succeeds and non-zero when execution
fails. Warning messages typically don’t effect the return code. What matters is did the script work or not?
Checking Return Codes In Your Script Commands
The environmental variable %ERRORLEVEL% contains the return code of the last executed program or script. A very
helpful feature is the built-in DOS commands like ECHO, IF, and SET will preserve the existing value
of %ERRORLEVEL%.
The conventional technique to check for a non-zero return code using the NEQ (Not-Equal-To) operator of
the IFcommand:
IF %ERRORLEVEL% NEQ 0 (
REM do something here to address the error
)
Another common technique is:
IF ERRORLEVEL 1 (
REM do something here to address the error
The ERRORLEVEL 1 statement is true when the return code is any number equal to or greater than 1. However, I don’t
use this technique because programs can return negative numbers as well as positive numbers. Most programs rarely
document every possible return code, so I’d rather explicity check for non-zero with the NEQ 0 style than assuming
return codes will be 1 or greater on error.
You may also want to check for specific error codes. For example, you can test that an executable program or script is
in your PATH by simply calling the program and checking for return code 9009.
SomeFile.exe
IF %ERRORLEVEL% EQU 9009 (
ECHO error - SomeFile.exe not found in your PATH
)
It’s hard to know this stuff upfront – I generally just use trial and error to figure out the best way to check the return
code of the program or script I’m calling. Remember, this is duct tape programming. It isn’t always pretty, but, it gets
the job done.
Conditional Execution Using the Return Code
There’s a super cool shorthand you can use to execute a second command based on the success or failure of a
command. The first program/script must conform to the convention of returning 0 on success and non-0 on failure for
this to work.
To execute a follow-on command after sucess, we use the && operator:
SomeCommand.exe && ECHO SomeCommand.exe succeeded!
To execute a follow-on command after failure, we use the || operator:
SomeCommand.exe || ECHO SomeCommand.exe failed with return code %ERRORLEVEL%
I use this technique heavily to halt a script when any error is encountered. By default, the command processor will
continue executing when an error is raised. You have to code for halting on error.
A very simple way to halt on error is to use the EXIT command with the /B switch (to exit the current batch script
context, and not the command prompt process). We also pass a specific non-zero return code from the failed
command to inform the caller of our script about the failure.
SomeCommand.exe || EXIT /B 1
A simliar technique uses the implicit GOTO label called :EOF (End-Of-File). Jumping to EOF in this way will exit your
current script with the return code of 1.
SomeCommand.exe || GOTO :EOF
Tips and Tricks for Return Codes
I recommend sticking to zero for success and return codes that are positive values for DOS batch files. The positive
values are a good idea because other callers may use the IF ERRORLEVEL 1 syntax to check your script.
I also recommend documenting your possible return codes with easy to read SET statements at the top of your script
file, like this:
SET /A ERROR_HELP_SCREEN=1
SET /A ERROR_FILE_NOT_FOUND=2
Note that I break my own convention here and use uppercase variable names – I do this to denote that the variable is
constant and should not be modified elsewhere. Too bad DOS doesn’t support constant values like Unix/Linux shells.
Some Final Polish
One small piece of polish I like is using return codes that are a power of 2.
SET /A ERROR_HELP_SCREEN=1
SET /A ERROR_FILE_NOT_FOUND=2
SET /A ERROR_FILE_READ_ONLY=4
SET /A ERROR_UNKNOWN=8
This gives me the flexibility to bitwise OR multiple error numbers together if I want to record numerous problems in
one error code. This is rare for scripts intended for interactive use, but, it can be super helpful when writing scripts you
support but you don’t have access to the target systems.
@ECHO OFF
SETLOCAL ENABLEEXTENSIONS
SET /A errno=0
SET /A ERROR_HELP_SCREEN=1
SET /A ERROR_SOMECOMMAND_NOT_FOUND=2
SET /A ERROR_OTHERCOMMAND_FAILED=4
SomeCommand.exe
IF %ERRORLEVEL% NEQ 0 SET /A errno^|=%ERROR_SOMECOMMAND_NOT_FOUND%
OtherCommand.exe
IF %ERRORLEVEL% NEQ 0 (
SET /A errno^|=%ERROR_OTHERCOMMAND_FAILED%
)
EXIT /B %errno%
If both SomeCommand.exe and OtherCommand.exe fail, the return code will be the bitwise combination of 0x1 and
0x2, or decimal 3. This return code tells me that both errors were raised. Even better, I can repeatedly call the bitwise
OR with the same error code and still interpret which errors were raised.
File Numbers
Each of these three standard files, otherwise known as the standard streams, are referernced using the numbers 0, 1,
and 2. Stdin is file 0, stdout is file 1, and stderr is file 2.
Redirection
A very common task in batch files is sending the output of a program to a log file. The > operator sends, or redirects,
stdout or stderr to another file. For example, you can write a listing of the current directory to a text file:
DIR > temp.txt
The > operator will overwrite the contents of temp.txt with stdout from the DIR command. The >> operator is a slight
variant that appends the output to a target file, rather than overwriting the target file.
A common technique is to use > to create/overwrite a log file, then use >> subsequently to append to the log file.
SomeCommand.exe > temp.txt
OtherCommand.exe >> temp.txt
By default, the > and >> operators redirect stdout. You can redirect stderr by using the file number 2 in front of the
operator:
DIR SomeFile.txt 2>> error.txt
You can even combine the stdout and stderr streams using the file number and the & prefix:
DIR SomeFile.txt 2>&1
This is useful if you want to write both stdout and stderr to a single log file.
DIR SomeFile.txt > output.txt 2>&1
To use the contents of a file as the input to a program, instead of typing the input from the keyboard, use
the <operator.
SORT < SomeFile.txt
Suppressing Program Output
The pseudofile NUL is used to discard any output from a program. Here is an example of emulating the Unix
command sleep by calling ping against the loopback address. We redirect stdout to the NUL device to avoid printing
the output on the command prompt screen.
PING 127.0.0.1 > NUL
Redirecting Program Output As Input to Another Program
Let’s say you want to chain together the output of one program as input to another. This is known as “piping” output to
another program, and not suprisingly we use the pipe character | to get the job done. We’ll sort the output of the DIR
commmand.
DIR /B | SORT
A Cool Party Trick
You can quickly create a new text file, say maybe a batch script, from just the command line by redirecting the
command prompt’s own stdin, called CON, to a text file. When you are done typing, hit CTRL+Z, which sends the end-
of-file (EOF) character.
TYPE CON > output.txt
There are a number of other special files on DOS that you can redirect, however, most are a bit dated like like LPT1 for
parallel portt printers or COM1 for serial devices like modems.
Checking that a File or Folder Exists
IF EXIST "temp.txt" ECHO found
Or the converse:
IF NOT EXIST "temp.txt" ECHO not found
Both the true condition and the false condition:
IF EXIST "temp.txt" (
ECHO found
) ELSE (
ECHO not found
)
NOTE: It’s a good idea to always quote both operands (sides) of any IF check. This avoids nasty bugs when a variable
doesn’t exist, which causes the the operand to effectively disappear and cause a syntax error.
Checking If A Variable Is Not Set
IF "%var%"=="" (SET var=default value)
Or
IF NOT DEFINED var (SET var=default value)
Checking If a Variable Matches a Text String
SET var=Hello, World!
IF "%var%"=="Hello, World!" (
ECHO found
)
Or with a case insensitive comparison
IF /I "%var%"=="hello, world!" (
ECHO found
)
Artimetic Comparisons
SET /A var=1
IF /I "%var%" EQU "1" ECHO equality with 1
IF /I "%var%" NEQ "0" ECHO inequality with 0
IF /I "%var%" GEQ "1" ECHO greater than or equal to 1
IF /I "%var%" LEQ "1" ECHO less than or equal to 1
Checking a Return Code
IF /I "%ERRORLEVEL%" NEQ "0" (
ECHO execution failed
)
Old School with GOTO
The old-school way of looping on early versions of DOS was to use labels and GOTO statements. This isn’t used much
anymore, though it’s useful for looping through command line arguments.
:args
SET arg=%~1
ECHO %arg%
SHIFT
GOTO :args
New School with FOR
The modern way to loop through files or text uses the FOR command. In my opinion, FOR is the single most powerful
command in DOS, and one of the least used.
GOTCHA: The FOR command uses a special variable syntax of % followed by a single letter, like %I. This syntax is
slightly different when FOR is used in a batch file, as it needs an extra percent symbol, or %%I. This is a very common
source of errors when writing scripts. Should your for loop exit with invalid syntax, be sure to check that you have
the %% style variables.
Looping Through Files
FOR %I IN (%USERPROFILE%\*) DO @ECHO %I
Looping Through Directories
FOR /D %I IN (%USERPROFILE%\*) DO @ECHO %I
Recursively loop through files in all subfolders of the %TEMP% folder
FOR /R "%TEMP%" %I IN (*) DO @ECHO %I
Recursively loop through all subfolders in the %TEMP% folder
FOR /R "%TEMP%" /D %I IN (*) DO @ECHO %I
Variable Substitution for Filenames
Functions are de facto way to reuse code in just about any procedural coding language. While DOS lacks a bona fide
function keyword, you can fake it till you make it thanks to labels and the CALL keyword.
There are a few gotchas to pay attention to:
1. Your quasi functions need to be defined as labels at the bottom of your script.
2. The main logic of your script must have a EXIT /B [errorcode] statement. This keeps your main logic from falling
through into your functions.
Defining a function
In this example, we’ll implement a poor man’s version of the *nix tee utility to write a message to both a file and the
stdout stream. We’ll use a variable global to the entire script, %log% in the function.
@ECHO OFF
SETLOCAL
:: script global variables
SET me=%~n0
SET log=%TEMP%\%me%.txt
:: The "main" logic of the script
IF EXIST "%log%" DELETE /Q %log% >NUL
:: do something cool, then log it
CALL :tee "%me%: Hello, world!"
:: force execution to quit at the end of the "main" logic
EXIT /B %ERRORLEVEL%
:: a function to write to a log file and write to stdout
:tee
ECHO %* >> "%log%"
ECHO %*
EXIT /B 0
Calling a function
We use the CALL keyword to invoke the quasi function labelled :tee. We can pass command line arguments just like
we’re calling another batch file.
We have to remember to EXIT /B keyword at the end our function. Sadly, there is no way to return anything other
than an exit code.
Return values
The return value of CALL will always be the exit code of the function. Like any other invokation of an executable, the
caller reads %ERRORLEVEL% to get the exit code.
You have to get creative to pass anything other than integer return codes. The function can ECHO to stdout, letting the
caller decide to handle the output by pipeling the output as the input to another executable, redirecting to a file, or
parsing via the FOR command.
The caller could also pass data by modifying a global variable, however, I try to avoid this approach.
Robust parsing of command line input separates a good script from a great script. I’ll share some tips on how I parse
input.
The Easy Way to read Command Line Arguments
By far the easiest way to parse command line arguments is to read required arguments by ordinal position.
Here we get the full path to a local file passed as the first argument. We write an error message to stderr if the file does
not exist and exit our script:
SET filepath=%~f1
IF NOT EXIST "%filepath%" (
ECHO %~n0: file not found - %filepath% >&2
EXIT /B 1
)
Optional parameters
I assign a default value for parameters as such
SET filepath=%dp0\default.txt
:: the first parameter is an optional filepath
IF EXIST "%~f1" SET filepath=%~f1
Switches
Named Parameters
Variable Number of Arguments
Reading user input
:confirm
SET /P "Continue [y/n]>" %confirm%
FINDSTR /I "^(y|n|yes|no)$" > NUL || GOTO: confirm
I use basic logging facilities in my scripts to support troubleshooting both during execution and after execution. I use
basic logging as a way to instrument what my scripts are doing at runtime and why. I remember watching a network
operations center trying to troubleshoot a legacy batch process where the sysadmins literrally had to try to read the
lines of a console window as they trickled by. This technique worked fine for years when the batch machines used dial-
up modems for connectivity to remote resources. However, the advent of brooadband meant the batch script executed
faster than anyone could read the output. A simple log file would have made troubleshooting work much easier for
these sysadmins.
Log function
I really like the basic tee implementation I wrote in Part 7 – Functions.
@ECHO OFF
SETLOCAL ENABLEEXTENSIONS
:: script global variables
SET me=%~n0
SET log=%TEMP%\%me%.txt
:: The "main" logic of the script
IF EXIST "%log%" DELETE /Q %log% >NUL
:: do something cool, then log it
CALL :tee "%me%: Hello, world!"
:: force execution to quit at the end of the "main" logic
EXIT /B %ERRORLEVEL%
:: a function to write to a log file and write to stdout
:tee
ECHO %* >> "%log%"
ECHO %*
EXIT /B 0
This tee quasi function enable me to write output to the console as well as a log file. Here I am reusing the same log
file path, which is saved in the users %TEMP% folder as the name of the batch file with a .txt file extension.
If you need to retain logs for each execution, you could simply parse the %DATE% and %TIME% variables (with the
help of command line extensions) to generate a unique filename (or at least unique within 1-second resolution).
REM create a log file named [script].YYYYMMDDHHMMSS.txt
SET
log=%TEMP%\%me%.%DATE:~10,4%_%DATE:~4,2%_%DATE:~7,2%%TIME:~0,2%_%TIME:~3,2%_%TIME:~6,2
%.txt
Taking a queue from the *nix world, I also like to include a prefix custom output from my own script as script:
some message. This technique drastically helps to sort who is complaining in the case of an error.
Displaying startup parameters
I also like to display the various runtime conditions for non-interactive scripts, like something that will be run on a
build server and redirected to a the build log.
Sadly, I don’t know of any DOS tricks (yet) to discrimintate non-interactive sessions from interactive sessions. C# and
.Net has the System.Environment.UserInteractive property to detect if this situation; *nix has some tricks
with tty file descriptors. You could probably hack up a solution by inspecting a custom environmental variable
like %MYSCRIPT_DEBUG% that defaults to being false.
Boilplate info
I like to include a header on all of scripts that documents the who/what/when/why/how. You can use the ::comment
trick to make this header info more readable:
:: Name: MyScript.cmd
:: Purpose: Configures the FooBar engine to run from a source control tree path
:: Author: [email protected]
:: Revision: March 2013 - initial version
:: April 2013 - added support for FooBar v2 switches
@ECHO OFF
SETLOCAL ENABLEEXTENSIONS ENABLEDELAYEDEXPANSION
:: variables
SET me=%~n0
:END
ENDLOCAL
ECHO ON
@EXIT /B 0
Conditional commands based on success/failure
The conditional operators || and && provide a convenient shorthand method to run a 2nd command based on the
succes or failure of a 1st command.
The && syntax is the AND opeartor to invoke a 2nd command when the first command returns a zero (success) exit
code.
DIR myfile.txt >NUL 2>&1 && TYPE myfile.txt
The || syntax is an OR operator to invoke a 2nd command when the first command returns a non-zero (failure) exit
code.
DIR myfile.txt >NUL 2>&1 || CALL :WARNING file not found - myfile.txt
We can even combined the techniques. Notice how we use the () grouping construct with && to run 2 commands
together should the 1st fail.
DIR myfile.txt >NUL 2>&1 || (ECHO %me%: WARNING - file not found - myfile.txt >2 &&
EXIT /B 1)
Getting the full path to the parent directory of the script
:: variables
PUSHD "%~dp0" >NUL && SET root=%CD% && POPD >NUL
Making a script sleep for N seconds
You can use PING.EXE to fake a real *nix style sleep command.
:: sleep for 2 seconds
PING.EXE -N 2 127.0.0.1 > NUL
Supporting “double-click” execution (aka invoking from Windows Explorer)
Test if %CMDCMDLINE% is equal to %COMSPEC% If they are equal, we can assume that we are running in an interactive
session. If not equal, we can inject a PAUSE into the end of the script to show the output. You may also want to change
to a valid working directory.
@ECHO OFF
SET interactive=0
ECHO %CMDCMDLINE% | FINDSTR /L %COMSPEC% >NUL 2>&1
IF %ERRORLEVEL% == 0 SET interactive=1
ECHO do work
IF "%interactive%"=="0" PAUSE
EXIT /B 0
La sintaxis normal del comando FOR es:
FOR %var IN (lista) DO (
comando
comando
...
)
Pero si lo vamos a usar dentro de un archivo BAT será así:
FOR %%var IN (lista) DO (
comando
comando
...
)
Observa que la variable "var" ahora va precedida por dos simbolos de "%". Además, si este for está dentro
de un archivo BAT, el nombre de la variable debe ser UNA SOLA LETRA (p.ej: %%n, %%i, %%j , etc )
EJEMPLO1
Para que la variable del FOR vaya tomando distintos valores dentro de una lista determinada:
for %A in (uno dos tres cuatro) do (
echo %A
)
Esto sacará por pantalla las palabras que están entre parentesis, separadas linea a linea.
Y si el "for" está dentro de un archivo BAT, y tome los valores posicionales que se pasan cuando se llama
al archivo desde la consola:
for %%x in (%*) do (
echo %%x
)
EJEMPLO2
Si queremos recorrer una lista de archivos de un determinado directorio (solo archivos, no directorios):
for %f in (*) do (
echo %f
)
y si queremos mover a la papelera de reciclaje algunos archivos con determinadas extensiones:
for %f in (*.jpg, *.mp3, *.bmp) do (
move %f c:\recycler
)
MEJORAS EN EL FOR
RECURSIVIDAD:
FOR /R [ruta] %V IN (lista) DO comando
DIRECTORIOS:
FOR /D %V IN (lista) DO comando
LISTA CON CONTADOR:
FOR /L %V IN (inicio, incremento, fin) DO comando
RECORRIDO DE TOKENS EN LINEAS DE TEXTO:
FOR /F ["tokens=... delims=..."] %V IN (archivo | 'comando' | "cadena")
DO comando
EJEMPLO3: (parametro /R)
Recorrer y mostrar todos los archivos de la unidad C: empezando en su directorio raiz, y recorriendo
recursivamente el resto de directorios que contiene:
for /R c:\ %v in (*) do (
echo %v
)
Una variacion de este ejemplo sería el buscar un determinado tipo de archivos dentro de un directorio
recursivamente. Voy a buscar todos los archivos "dll" y "exe" dentro del directorio "windows":
for /R c:\windows %v in (*.dll, *.exe) do (
echo %v
)
EJEMPLO4: (parametro /D)
Si lo que me interesa es listar los directorios en vez de los archivos:
for /D %v in (*) do (
echo %v
)
Y si lo quiero hacer recursivamente puedo añadir "/R" al comando anterior:
for /R /D %v in (*) do (
echo %v
)
Y si quiero hacerlo recursivamente desde un directorio concreto (p.ej: c:\windows):
for /R c:\windows /D %v in (*) do (
echo %v
)
EJEMPLO5: (parametro /L)
Para crear un tipico bucle contador de 1 a 10, saltando de 1 en 1:
for /L %x in (1, 1, 10) do (
echo %x
)
Y saltando de 2 en 2
for /L %x in (1, 2, 10) do (
echo %x
)
Y de 3 en 3:
for /L %x in (1, 3, 10) do (
echo %x
)
etc.
Hay que observar que el primer numero dentro del parentesis es el valor inicial que tomará la variable
"%x", el segundo numero es el incremento que sufrirá dicha variable en la proxima iteracion del FOR, y el
tercer número es el valor máximo que tomará dicha variable y que cuando alcance o supere dicho valor, el
bucle FOR terminará de ejecutarse.
EJEMPLO6:
Archivo BAT que crea varios archivos vacios y los llama a todos con el mismo nombre, pero terminados en
un numero diferente:
@echo off
cls
set/p nombre=Indica el nombre de los archivos a crear:
set/p num=Cuantos archivos hay que crear?:
for /L %%x in (1, 1, %num%) do (
echo 2> %%x%nombre
)
EJEMPLO7: (parametro /F)
Recorrer un archivo y mostrar solo la primera palabra de cada linea:
for /F %%x in (fichero.txt) do (
echo %%x
)
El FOR va recorriendo todas las lineas, y cada linea se ha dividido en "tokens" (token=palabra). La
variable del for almacena la primera palabra de cada linea.
EJEMPLO8: (parametro /F con tokens)
Podemos seleccionar varios tokens mediante la clausula tokens=. Los distintos tokens se irán guardando
automáticamente en variables alfabeticamente consecutivas a partir de la variable creada en el for.
En el siguiente ejemplo nos quedamos con los tokens (palabras) 1, 3 y 5 de cada linea:
for /F "tokens=1,3,5" %%a in (fichero.txt) do (
echo %%a %%b %%c
)
observa que aunque yo solamente he definido la variable "%%a" en el FOR, las variables "b" y "c" se
crean automaticamente.
Podemos escoger rangos, como en el siguiente ejemplo, en el que vamos a escoger los tokens del 1 al 3,
y además el token 5
for /F "tokens=1-3,5" %%a in (fichero.txt) do (
echo %%a %%b %%c %%d
)
O si queremos coger la linea completa a partir de la septima palabra:
for /F "tokens=7*" %%a in (fichero.txt) do (
echo %%a
)
Y si queremos coger la linea completa:
for /F "tokens=*" %%a in (fichero.txt) do (
echo %%a
)
EJEMPLO8: (parametro /F con delimitadores)
Además de la clausula "tokens" con el parámetro "/F", podemos usar la clausula "delims", que indica la
separacion entre los distintos tokens. Por defecto, los caracteres delimitadores entre tokens son los
espacios en blanco y los tabuladores.
En el siguiente ejemplo anulamos los delimitadores y obtenemos lo mismo que antes:
for /F "delims=" %%a in (fichero.txt) do (
echo %%a
)
Si queremos usar como delimitadores los simbolos de puntuacion, como el punto, la coma, el punto y
coma, etc...:
for /F "delims=.,;:" %%a in (fichero.txt) do (
echo %%a
)
esto solo imprimirá por pantalla la linea completa hasta que encuentre alguno de los delimitadores que le
hemos indicado.
También se pueden combinar delimitadores y tokens:
for /F "tokens=7* delims=,." %%a in (fichero.txt) do (
echo %%a
)
También se pueden usar otras cláusulas como:
skip=n, que se saltaría las n primeras líneas del archivo, empezando a procesar la n+1
eol=carácter, que interpreta las líneas que comienzan por ese carácter como líneas de
comentarios y se las salta.
useback, que cambia la semantica de la lista: (`comando`), ('cadena'), (archivo) ("archivo1"
"archivo2" "archivo3")
EJEMPLO9: (uso de comandos dentro de la Lista)
Se puede sustituir la lista de valores que tiene que tomar la variable, por la ejecución de un comando,
como en el siguiente ejemplo:
for /F "tokens=15 delims=:" %%a in (ipconfig ^| find IP) do (
echo %%a
)
Observar el caracter de escape "^" necesario para que la tubería se interprete dentro del comando en vez
de ser interpretado para el for
EJEMPLO10: (parámetro /F con cadenas)
Podemos extraer distintas partes del valor de una variable. Por ejemplo, si mostramos el valor de la
variable "date", nos dará una fecha con el siguiente formato:
07/05/2012
donde el dia, la fecha y la hora están separados por un carácter que sirve de delimitador: "/"
Para extraer las distintas partes de la fecha utilizamos el siguiente ejemplo (dentro de un archivo BAT):
for /F "tokens=1-3 delims=/:" %%a in (%date%) do (
echo Hoy es %%a del mes %%b del año %%c
)
lo cual nos proporciona la siguiente salida por pantalla:
Hoy es 07 del mes 05 del año 2012
EJEMPLO 11: Variables dentro de un FOR
Hay veces que necesitamos usar y actualizar otras variables en el FOR, a parte de la que se crea en la
cabecera del mismo, o incluso anidar un FOR dentro de otro FOR.
Para poder acceder a dichas variables hay que poner al principio del archivo BAT la siguiente linea (es
MUY MUY IMPORTANTE ponerlo, porque sino no funcionará bien nuestro programa BAT):
setlocal enabledelayedexpansion
y además para acceder al valor de dichas variables hay que usar el simbolo de admiración "!", en lugar del
simbolo "%"
Por ejemplo, el siguiente archivo BAT nos muestra la tabla de multiplicar de un numero que yo le indique
por teclado:
tabla.bat
@echo off
cls
setlocal enabledelayedexpansion
rem En la variable num guardo que tabla de multiplicar quiero ver
set /p num=Quieres ver la tabla de multiplicar del numero...
cls
echo TABLA DEL %num%
echo ===============
echo .
for /L %%a in (1,1,10) do (
set /a result=%num%*%%a
echo %num% * %%a = !result!
rem Hay que observar que para acceder al valor de la variable
rem "result" hay que cambiar los caracteres de porcentaje "%"
rem por caracteres de admiracion "!"
)
Si quiero ver todas las tablas de multiplicar, debo anidar un FOR dentro de otro, y el archivo BAT quedaría
así:
todastablas.bat
@echo off
cls
setlocal enabledelayedexpansion
for /L %%i in (1,1,10) do (
echo TABLA DEL %%i
echo ===============
echo .
for /L %%a in (1,1,10) do (
set /a result=%%i*%%a
echo %%i * %%a = !result!
)
pause
cls
)
Si no queremos usar el comando "setlocal enabledelayedexpansion" podemos ejecutar nuestro archivo
BAT desde un terminal con "sustitución retardada". Para ello ejecutamos lo siguiente:
cmd /v:on
PETICIONES DE ARCHIVOS BAT DE LOS USUARIOS
Aquí iré añadiendo, cuando tenga tiempo, las soluciones a lo que me vais planteando los que comentais
en esta entrada.
El usuario Nano me preguntó:
"Me gustaría crear un archivo bat, el cual me mostrara la fecha de creación de un archivo.
el resultado debería ser:
La fecha del archivo es: 20/05/2013"
SOLUCIÓN:
@echo off
cls
echo Este programa BAT te pide el nombre de un archivo y te muestra la fecha en
la que fue creado
dir
echo.
rem en la variable "archivo" meto el nombre del archivo
set /p archivo="Introduce el nombre del archivo:"
cls
rem ahora con el siguiente "for" extraigo (con el comando "find") la unica
linea donde estan los caracteres "/" del listado que me saca el comando dir,
porque ahi esta la fecha que quiero obtener
rem es muy importante poner las comillas simples en su lugar correspondiente
rem y tambien es muy importante poner el acento circunflejo "^" justo antes del
caracter filtro "|", porque sino no funcionara
for /F "tokens=1" %%x in ('dir %archivo% ^| find "/"') do (
echo El archivo %archivo% fue creado el %%x
)
La usuaria Alejandra me preguntó:
"Quiero recorrer a partir de un directorio todos los archivos y renombrar los que tienen una extension, por
ejemplo jpg
tendria que renombrar todos incusive si hay subdirectorios."
Esto NO SE PUEDE HACER, porque a cada archivo le tendrías que poner un nombre diferente (no puede
haber 2 o más archivos que tengan el mismo nombre y la misma extensión), tendrías que ir cambiandoselo
uno por uno.
Sin embargo, si puedo cambiar la extensión de todos los archivos de un determinado directorio, que
tengan una extensión en concreto (por ejemplo ".avi", ".mp3", o cualquier otra), este sería el archivo BAT:
SOLUCION
@echo off
setlocal enabledelayedexpansion
cls
echo Este archivo BAT recorre un directorio y sus subdirectorios y renombra los
archivos que tengan una determinada extension:
echo.
echo.
set /p dir="Introduce la ruta del directorio:"
set /p ext="Introduce la extension de los archivos que se van a cambiar:"
set /p nueva="Introduce la nueva extensión que van a tener esos archivos:"
echo.
echo.
rem Me situo en el directorio en cuestion
cd %dir%
rem Cambio la extension de los archivos del directorio actual
ren *.!ext! *.!nueva!
rem Con el siguiente "for" me voy metiendo en los subdirectorios del directorio
actual y les voy cambiando la extension a los archivos elegidos
for /D /R %%x in (*) do (
cd %%x
ren *.!ext! *.!nueva!
cd ..
)
El usuario Anonimo me preguntó:
"Quiero hacer un archivo BAT que: Programe la ejecución de una copia de seguridad del contenido de una
carpeta a otra a la hora que se pase como parámetro."
SOLUCION:
Aqui hay que preguntar 3 cosas al usuario: la carpeta que quiere copiar, la carpeta destino, y la hora a la
que se efectuará esa copia. Y después usar el comando "at" para programar la tarea a una hora
determinada, y el comando "xcopy" para copiar un directorio con todo su contenido.
@echo off
cls
set /p origen="Escribe la ruta de la carpeta que quieres copiar:"
set /p destino="Escribe la ruta de destino"
set /p hora="Escribe la hora a la que se hara esta copia: hh:mm"
at %hora% xcopy %origen% %destino%
Pero si la hora se la pasamos desde la linea de comandos sería así:
@echo off
cls
set /p origen="Escribe la ruta de la carpeta que quieres copiar:"
set /p destino="Escribe la ruta de destino"
at %1 xcopy %origen% %destino%
El usuario Anonimo también me preguntó:
"Quiero hacer un archivo BAT que: Muestre el nombre y tamaño de los archivos de la carpeta
activa cuyo tamaño sea superior a la cantidad que se indique como parámetro"
SOLUCION:
Con un for hay que ir recorriendo todos los archivos del directorio actual, y comparar su tamaño con el
número de bytes que se le ha pasado como parametro posicional número 1 (%1).
@echo off
set enabledelayedexpansion
cls
echo Los archivos mas grandes de %1 bytes son:
echo.
REM Recorro todos los archivos del directorio actual y comparo si
REM su tamaño es mayor que el tamaño del archivo pasado por la
REM linea de comandos
for %%a in (*) do (
for /F "tokens=3" %%t in ('dir /N /-C %%a ^| find "/"') do (
if %%t gtr %1 echo %%a = %%t bytes
)
)
REM He usado el caracter "/" para filtrar las lineas generadas
REM por el comando dir, puesto que las lineas que contienen ese
REM caracter, son las que tienen una fecha, y por tanto tienen
REM los datos de un archivo concreto.
REM Además uso las opciones /N y /-C del comando dir para que
REM se muestren todos los datos de los archivos, entre ellos
REM el tamaño, y la opcion /-C evita que aparezca el separador
REM de miles en el tamaño del archivo, que luego al hacer la
REM comparación me dará problemas si aparece.
El usuario Victor Castillejo me preguntó:
"Quiero hacer un archivo BAT que: me muestre la linea numero 4 de un archivo en concreto"
He hecho un archivo bat mejor que te pida el nombre de un archivo, y una linea inicial y una final y te
imprima todas las lineas que están entre ambos numeros
SOLUCION:
@echo off
cls
setlocal enabledelayedexpansion
set/p nombre=Indica el nombre del archivo:
set/p numero=Indica el numero de linea inicial que quieres mostrar:
set/p final=Indica el numero de linea final que quieres mostrar:
set num=1
for /f "tokens=*" %%a in (%nombre%) do (
if !num! geq %numero% (
if !num! leq %final% echo %%a
)
set /a num = !num! + 1
)
El usuario Anonimo me preguntó:
"Quiero hacer un archivo BAT que me muestre las 30 ultimas lineas de un archivo en concreto"
He hecho un archivo bat mejor que te pida el nombre de un archivo, y las lineas finales, y te imprima las
lineas finales que el usuario indique
SOLUCION:
@echo off
cls
setlocal enabledelayedexpansion
set/p nombre=Indica el nombre del archivo:
set/p lineas=Indica cuantas lineas quieres mostrar del final del
archivo:
set num=1
REM Con el siguiente for contare cuantas lineas tiene el archivo
for /f "tokens=*" %%a in (%nombre%) do (
set /a num = !num! + 1
)
echo El archivo %nombre% tiene %num% lineas. Las ultimas %lineas% lineas son
las siguientes:
echo.
echo.
REM En la variable inicio estara el numero de la linea desde la que tenemos que
imprimir por pantalla
set /a inicio = !num! - !lineas!
set num=1
for /f "tokens=*" %%a in (%nombre%) do (
if !num! geq %inicio% (
echo %%a
)
set /a num = !num! + 1
)
El usuario Fran me preguntó:
"Quiero hacer un archivo BAT que lea un fichero que tiene un indice (un numero al principio de cada linea)
y que las lineas que estan entre 0 y 249 las guarde dentro de un archivo (archivo1.txt) y las restantes
lineas las guarde en otro archivo (archivo2.txt)"
SOLUCION:
@echo off
cls
setlocal enabledelayedexpansion
REM Los archivos resultantes van a ser "archivo1" y "archivo2"
REM Al principio, estos archivos deben estar vacios
echo. > archivo1.txt
echo. > archivo2.txt
set/p nombre=Indica el nombre del archivo:
REM ahora tomare las lineas del archivo de una en una
REM leyendo su primer token, que sera el indice, y el
REM resto de la linea, que sera lo que meta en el fichero
REM resultante
for /f "tokens=1,*" %%a in (%nombre%) do (
if %%a lss 250 (
echo %%a %%b >> archivo1.txt
) else (
echo %%a %%b >> archivo2.txt
)
)
El usuario Angel (anonimo) me preguntó:
"Quiero hacer un archivo BAT que recorra el árbol que cuelga de un directorio, y me copie un archivo
determinado en cada uno de los directorios de dicho árbol"
SOLUCION:
@echo off
REM Guardo en la variable ruta la ruta del directorio actual
set ruta=%cd%
set /p nombre=Escribe el archivo del directorio actual que quieres copiar:
REM Ahora en la variable ruta, genero la ruta absoluta del
REM archivo que quiero copiar
set ruta=%ruta%\%nombre%
REM Con el siguiente FOR recorro recursivamente todos los
REM directorios del directorio actual y copio el archivo
REM que he seleccionado dentro de ellos
for /R /D %%v in (*) do (
copy "%ruta%" "%%v\%nombre%"
)
El usuario Jorge Rainof me preguntó:
"Quiero hacer un archivo BAT que sume los datos numericos que se encuentran en las lineas de un fichero
de texto. Estos numeros tienen separador de miles"
SOLUCIÓN:
@echo off
cls
setlocal enabledelayedexpansion
set suma=0
set /p archivo=Que archivo contiene los numeros para sumar?:
for /f "tokens=1-5 delims=." %%a in (!archivo!) do (
set num=%%a%%b%%c%%d%%e
set /a suma=!suma! + !num!
echo + !num!
)
echo ------------------------
echo !suma!
pause
OTRA SOLUCIÓN (propuesta por Jorge Rainoff):
@echo off
cls
setlocal enabledelayedexpansion
set suma=0
set /p archivo=Que archivo contiene los numeros para sumar?:
REM en el siguiente "for", a diferencia del anterior, solo
REM voy a coger el primer "token", asi que no hace falta
REM que lo indique explicitamente en el "for".
REM En la variable "%%a" estará el número que quiero sumar,
REM y para quitarle los puntos intermedios, asigno su valor
REM a otra variable llamada "num", y a ésta le quito los
REM puntos con la siguiente instrucción: "set num=!num:.=!"
for /f %%a in (!archivo!) do (
set num=%%a
set num=!num:.=!
echo + !num!
set /a suma= !suma! + !num!
)
echo ------------------------
echo !suma!
pause
El usuario Anonimo me preguntó:
"Quiero hacer un archivo BAT que copie el ultimo archivo modificado a un directorio"
SOLUCIÓN:
@echo off
cls
setlocal enabledelayedexpansion
REM Este programa BAT copiara en el directorio "copia"
REM el ultimo fichero modificado en el directorio actual
set num=1
for /f "tokens=*" %%a in ('dir /o:-d /a:-d /b') do (
if !num! equ 1 (
echo El archivo modificado mas reciente es: %%a
copy "%%a" copia
dir copia\%%a
)
set num=2
)
El usuario Fernando me preguntó:
"Quiero hacer un archivo BAT que extraiga un caracter de una variable usando un FOR"
Esto no lo puedes hacer con un for.
En los lenguajes de programación como Pascal, Java, C, etc. , existen funciones específicas que sirven
para extraer una subcadena que se encuentre dentro de una cadena de caracteres, pero en la
programación de archivos BAT no hay ningún comando que haga esto directamente (o por lo menos yo no
lo conozco).
Se puede hacer una especie de bucle (usando etiquetas e instrucciones goto) que vayan pasando por el
primer caracter de una variable ( usando " echo %variable:~0,1% " ) y lo vayamos desplazando un lugar
hacia la izquierda ( usando " set variable=%variable:~1% " ). Así haremos que se vayan imprimiendo por
pantalla todos los caracteres de la variable, linea por linea.
SOLUCIÓN:
@echo off
setlocal enabledelayedexpansion
cls
set /p frase="Escriba una frase: "
:bucle
if "%frase%" equ "" goto fin
set letra=%frase:~0,1%
set frase=%frase:~1%
goto bucle
:fin
pause
El usuario Mauricio Espinosa Bustos me preguntó:
"Quiero hacer un archivo BAT que elija el archivo de mayor tamaño de un mes y un año concretos, cuyo
nombre empiece por TARRO.D[fecha]"
Supongo que la fecha tiene este formato: dd-mm-aaaa
SOLUCIÓN:
@echo off
cls
setlocal enabledelayedexpansion
REM Este programa BAT mostrará cual es el archivo mayor
REM del directorio actual, que empieza por TARRO.D[fecha]
set /p mes="Indica el mes con dos digitos : "
set /p anio="Indica el anio con 4 digitos : "
set num=1
for /f "tokens=*" %%a in ('dir /o:-s /a:-d /b "TARRO.D*-%mes%-%anio%"') do (
if !num! equ 1 (
echo El archivo de mayor tamanio del mes %mes% es: %%a
)
set num=2
)
Mi amigo y compañero Carlos Trujillo me comentó el otro día :
"Quiero hacer un archivo BAT que me cree automaticamente carpetas para cada dia del mes de un
determinado año, para guardar las fotos que voy haciendo en ellas, clasificadas por días"
SOLUCIÓN:
@echo off
cls
setlocal enabledelayedexpansion
set /p mes="Escribe el mes : "
set /p anio="Escribe el anio : "
REM Voy a preguntar cuantos dias tiene el mes
REM para saber cuantas carpetas tengo que hacer
set /p dias="Cuantos dias tiene este mes? :"
for /L %%d in ( 1 , 1 , %dias% ) do (
mkdir "fotos %%d-%mes%-%anio%"
)
El usuraio Alcides Dominguez García preguntó :
"Tengo el archivo "datos.txt" que es como el siguiente:
86134 31965 01706 10304 20243 30011 40096 53006 61254 70500 333 10377 55103=
86170 32970 01604 10286 20203 39988 40089 53003=
86185 NIL=
86192 32970 00000 10282 20183 39895 40109 63204 52004=
86210 32570 11802 10302 20225 39769 40103 52020 81200 333 10374 55110
81833=
86218 31960 01504 10284 20219 30021 40116 53005 70400
55103=
en el que cada linea termina en el caracter "=". Quiero obtener aquellos valores de cada linea que
empiecen por un numero concreto"
SOLUCIÓN:
@echo off
cls
setlocal enabledelayedexpansion
REM Voy a pedir al usuario que me diga que numeros quiere
REM ver por pantalla, dependiendo de su primer digito
set /p num=Por que digito empiezan los numeros que estas buscando? (0-9) :
REM voy a ir extrayendo linea por linea del archivo
REM "datos.txt" teniendo en cuenta que el caracter "="
REM marca el final de una linea
for /f "tokens=1 delims==" %%a in (datos.txt) do (
set linea=%%a
REM ahora voy recorriendo cada dato de la linea extraida
for %%b in (!linea!) do (
set dato=%%b
REM comparo el primer digito de la variable "dato" con
REM el criterio de busqueda que le indique al principio
REM y si coinciden lo muestro por pantalla
if "!dato:~0,1!" == "!num!" echo !dato!
)
)
El usuraio Anonimo preguntó :
"Tengo el archivo "datos2.txt" que es como el siguiente:
000001 texto
000003 texto
000004 texto
000007 texto
..
en el que cada linea empieza por un numero de 6 digitos rellenado con ceros a la izquierda. Los numeros
de esas lineas no son correlativos. ¿Como podría corregirlos automaticamente para que si lo fueran?"
SOLUCIÓN:
@echo off
cls
setlocal enabledelayedexpansion
set relleno=000000
set num=1
echo. > temporal.txt
REM recorro linea por linea el archivo "datos2.txt", le
REM quito el numero de 6 cifras que tiene al principio
REM para despues ponerle otro numero de 6 cifras
REM correctamente numerado, empezando por el 000001
for /f "tokens=1,*" %%a in (datos2.txt) do (
set num2=!relleno!!num!
set num2=!num2:~-6!
echo !num2! %%b >> temporal.txt
set /a num=!num!+1
)
REM Ahora sustituyo el archivo temporal.txt por datos2.txt
type temporal.txt > datos2.txt
del temporal.txt
pause
El usuraio Anonimo preguntó :
"Tengo varios archivos de texto, que contienen información. Quiero extraer automaticamente de cada uno
de ellos las lineas que están entre las cadenas de caracteres "DISPENSER ERROR" y "RCLen".
He creado un archivo bat para extraer esas lineas de un archivo llamado "datos2.txt", aqui está la
solución:
SOLUCIÓN:
@echo off
cls
setlocal enabledelayedexpansion
REM con el comando "find /n" voy a buscar la linea en la que
REM aparece la cadena de caracteres "DISPENSER ERROR", junto
REM con su numero de linea. Lo guardo en una variable
REM llamada inicio
for /f %%a in ('find /n "DISPENSER ERROR" datos2.txt ^| more
+2') do (
set inicio=%%a
)
REM ahora busco el numero de linea en la que aparece "RCLen"
REM y lo guardo en la variable "fin"
for /f %%a in ('find /n "RCLen" datos2.txt ^| more +2') do (
set fin=%%a
)
REM ahora necesito extraer el numero que se encuentra entre
REM los Corchetes [45], de la variable inicio, porque en
REM esa linea se encuentran "DISPENSER ERROR". Para ello
REM voy a hacer el siguiente bucle
set inicio=!inicio:~1!
set ini=
:bucle1
if "!inicio:~0,1!" == "]" goto :continuar
set ini=!ini!!inicio:~0,1!
set inicio=!inicio:~1!
goto bucle1
:continuar
REM ahora extraigo el numero de linea en el que se encuentra
REM la cadena RCLen, con el siguiente bucle
set fin=!fin:~1!
set final=
:bucle2
if "!fin:~0,1!" == "]" goto :continuar2
set final=!final!!fin:~0,1!
set fin=!fin:~1!
goto bucle2
:continuar2
REM ahora en las variables "ini" y "final" tengo los numeros
REM de las lineas que debo mostrar del archivo datos2.txt
set num=1
for /f "tokens=*" %%a in (datos2.txt) do (
if !num! geq !ini! (
if !num! leq !final! (
echo %%a
)
)
set /a num=!num!+1
)