I use Ruby a lot on Windows and it’s quite common to use a simple Command file to launch the script, especially when scheduling it using something like Windows Scheduler or PyCron. When launching a Command script in Windows, it will usually have an empty environment and will launch in something like c:\windows\system32
instead of the directory where the command scripts is. Often, it’s quite useful to move to the directory of the script so that everything works with relative paths.
This post is just a note for me to be able to remember the details of how to do this.
The simple way to do this is to edit the command file directly. Let’s say that the command file is in d:\work
and you’d like to move to this path before running the rest of the script, the easy way is to add this to the top of the file:
D:\
cd \work
Note that the second line could be cd \work
or cd d:\work
but it’s important that this have either the full path on D:\ or at least start with a \ since that will ensure that the path changes correctly. If you just have it as D:\
and cd work
it could fail for a few reasons. Try it on command prompt to get a feel of the things that could go wrong.
However, this expample is helpful and illustrative since it tells us what we need to do:
- Identify the drive of the file and change to that drive
- Identify the directory of the file and change to that directory
- Run the rest of it
Short Version
This is basically it!
:: Shift directories to the correct path
%~d0
cd %~dp0
Longer version – the explanation
If you want to know what this does, here are the details. What you need to know is that when a command is called, there are parameters passed to it. The actual arguments passed to the script start from 1 but the script itself is parameter 0.
Now, to try out what each of the parts does, create a file called t.cmd
in some folder and add this to it:
echo off
echo Param0 is %0
echo Drive0 is %~d0
echo Path0 is %~dp0
Run it as t.cmd
and see the output you get – here is what I get (the script is in e:\blog)
E:\blog>echo off
Param0 is t.cmd
Drive0 is E:
Path0 is E:\blog\
So, what we see is:
- %0 gives us the name with which the command is called
- ~d0 gives us the drive of the command script
- ~dp0 gives us the full directory path of the script (without the script name)
This then gives you a clear idea of why the commands in the previous section work:
- Change drive
- Change to the full path
Bonus – returning to the Launch Directory
My main need is met by what’s written above. However, some times, it is quite annoying that the directory has changed (especially when run interactively). If you want to allow the script to come back to the directory from where it was launched, you need to use a pair of other commands: pushd
and popd
.
The final command file will look something like this then:
:: Save the directory where we are
pushd %CD%
:: Shift directories to the correct path
%~d0
cd %~dp0
:: do what we need to do
:: do what else we need to do
:: Restore the directory where we started from
popd
For this, we need to know 3 things:
%CD%
at the start of the command file holds the directory in which the command file is launchedpushd
pushes a directory path to the stack – this is the parameter passed topushd
. It also moves to that directory.popd
pops the directory path off the stack. It also moves to that directory.
So, if you pushd
a directory, it will be saved on the top of the stack; when you do a popd
, it will be taken off the stack and passed back to your script. So, the first bit saves the path on the stack and the second bit retrieves it so that we can use it. (This assumes that any other things pushed on to the stack have been properly retrieved before the popd is called).
As you see, we are doing this:
pushd %CD%
saves the launch directory- At the end we do
popd
to retrieve and move to the launch directory
Further Reading
Most of this information is based on information found from the following:
- Command line arguments are explained at https://ss64.com/nt/syntax-args.html (read the d0 and dp1 bits)
- Details of pushd – https://docs.microsoft.com/en-us/windows-server/administration/windows-commands/pushd
- Details of popd – https://docs.microsoft.com/en-us/windows-server/administration/windows-commands/popd
- A helpful discussion – https://stackoverflow.com/questions/17063947/get-current-batchfile-directory