pathnames with spaces in batch script - windows

I have a problem with spaces in directory names in a batch script.
I store a base directory and then use that to make subdirectories and files, something like:
set basepath=c:\some\path
set logdir=%basepath%\log
set logfile=%logdir%\test.log
But the basepath on some servers have spaces in it. Earlier I used dir /x to get the shortened 8.3 names but I encountered one server where this doesn't work (apparently there is some setting to disable this, and I don't have privileges to turn it back on). So now I'm trying to figure this out. I need to concatenate filename/directories to basepath, which may have spaces in it. I tried using double quotes, but it didn't work.
At the command prompt, you can do things like cd "some path"\with\spaces using a combination of double quoted directories and non-double-quoted directories. But this doesn't work in a batch script.
Any suggestions?

set "basePath=c:\somewhere\over the rainbow"
set "logDir=%basePath%\logs"
set "logFile=%logDir%\kansas.log"
>> "%logFile%" echo This is a test
cd "%logDir%"
Don't insert quotes inside the variable values (unless it is necessary).
Use quotes surounding the set command to ensure no aditional spaces are stored in variables and to protect special characters.
Place quotes in the correct places in the final commands that make use of the variables.

Put double quotes around the environment variable only when you need to actually use it.
set basepath=c:\some\path with spaces
set logdir=%basepath%\log
xcopy *.log "%logdir%"
Then reference it as "%logdir%" and it will expand to "c:\some\path with spaces\log". This works because set puts everything after the = except for including trailing white-space into the environment variable.

Related

disable histexpand and variable substitution

I need to create many thousands of files and I have no control over the text strings that need to be used for the paths and names. Trouble is, these strings might contain ",',“,‘,! or $, all of which can cause problems.
I can replace all quotes with the normal apostrophe, but I want to keep any $ or ! characters and so far not been able to figure how to do this.
Set +H will turn off history expansion, but I cannot make it work within the same command. So:-
set +H; echo "Hi, this is $10 Tom!"
still generates the error due to the !. If I run them as 2 separate commands, histexpand stays off and it works, but running them both just separated by the ; does NOT change histexpand.
The problem is that the commands will be run in their own shell and I can't seem to run multiple lines (doShellScript in Apple's JXA) so need them on the same line just separated by the ;.
So how can I make the set +H stick for the immediately following command?
Also, is it possible to stop the shell from interpreting $ as preceding a variable and just deal with it as a regular character? I can't just quote the whole string with single quotes since it may contain ' within itself.
Suggestions?

cd to an unknown directory name with spaces in a bash script

I've looked at some of the posts that have similar issues, but I can't extrapolate some of the solutions to fit my own needs, so here I am.
I have a simple shell script and I need it to cd into a directory with a space in the name. The directory is in the same place every time (/home/user/topleveldir) but the directory name itself is unique to the machine, and has a space in it (/home/user/topleveldir/{machine1}\ dir/, /home/user/topleveldir/{machine2}\ dir/). I'm confused as to the best method to cd into that unique directory in a script.
I don't see why something like following would not work
baseDir=/home/user/topleveldir
machine=<whatever machine name>
cd "$baseDir/$machine dir"
You need to quote that space character, so that the shell knows that it's part of the argument and not a separator between arguments.
If you have the directory directly on that command line in the script, use single quotes. Between single quotes, every character is interpreted literally except a single quote.
cd '/home/user/topleveldir/darkstar dir/'
If the directory name comes from a variable, use double quotes around the command substitution. Always use double quotes around command substitutions, e.g. "$foo". If you leave out the quotes, the value of the variable is split into separate words which are interpreted as glob patterns — this is very rarely desirable.
directory_name='darkstar dir'
…
cd "/home/user/topleveldir/$directory_name"

CMD: Check for quotes

Let's say, the user drag and drops an file into my batch file, which causes that the batch file copies the file to a certain directory. the problem is the following command:
copy "%1" "C:\path\to\it"
The problem here is the quotes around%1. When you drag and drop something in a batch file, normally, it wouldn't put quotes, so everything's fine. But when i convert my batch file to EXE, it actually puts quotes there.
So, what i want to do is, checking if the file does have quotes, if not, than do the command above, otherwise, do the command without quotes.
Thanks.
Would the following work?
copy %1 "C:\Dir1\Dir2"
my few attempts to find a problem not quoting %1 have not resulted in adverse effects.
Not sure if the answer given here was what you were seeking, and I may be a couple of years late, but I would like to offer an alternate solution to your quoting problem as I have run into it something similar myself. Maybe it will benefit someone else.
You ARE able to strip the quotes from around variables, including the ones that are dragged and dropped. Here's how:
add a tilde to the %n variable (e.g., copy %~1 "C:\path\to\it")
For other variables within the batch file, use a similar technique, this time performing a substitution of the double-quote for nothing :"=, as in:
set filename="C:\path\to\it"
echo %filename% (will give you "C:\path\to\it")
set noquotefilename=%filename:"=%
echo %noquotefilename% (will give you C:\path\to\it without the quotes)
It is not my original solution, but I found it near the bottom of the following post:
Removing double quotes from variables in batch file creates problems with CMD environment
The substitution technique has other applications, as you could easily substitute any character for any other (e.g., :\=_ to substitute a back-slash for an underscore).
Hope this helps!
The problem is the process by which you are converting to EXE. Try a different BAT to EXE converter.

Batch file equivalent of Unix parameter expansion with quotes

There have been a lot of questions asked and answered about batch file parameters with regards to the %*, but I haven't found an answer for this.
Is there an equivalent syntax in batch files that can perform the same behavior as "$#" in Unix?
Some context:
#echo off
set MYPATH=%~dp0
set PYTHON=%MYPATH%..\python\python
set BASENAME=%~n0
set XTPY=%MYPATH%..\SGTools\bin\%BASENAME%.py
"%PYTHON%" "%XTPY%" %*
This is the .bat file that is being used a proxy to call a Python script. So I am passing all the parameters (except the script name) to the Python script. This works fine until there is a parameter in quotes and/or contains spaces.
In shell scripts you can use "$#" to take each parameter and enclose it in quotes. Is there something I can do to replicate this process?
Example calls:
xt -T sg -t "path with possible spaces" -sum "name with spaces" -p <tool_name> -o lin32 lin64 win32 <lots of other options with possibilities of spaces>
The command/file xt simply contains the code listed above, because the actual executable is Python code in a different folder. So the point is to create a self-contained package where you only add one directory (xbin directory) to your path.
I'm not sure what the cleanest solution is, but here is how I worked around the problem:
setlocal EnableDelayedExpansion
for %%i in (%*) do set _args= !_args! "%%~i"
echo %_args%
%_args% will now contain a quoted list of each individual parameter. For example, if you called the batch file as follows:
MYBATFILE "test'1'file" "test'2'file" "test 3 file"`
echo %_args%
will produce the original quoted input.
I needed this for CMD files that take unfriendly file or directory names and pass them to Cygwin Bash shell scripts which do the heavy lifting, but I couldn't afford to have the embedded single quotes or spaces lost in the transition.
Note the ~i in %%~i% which is necessary to remove quotes before we apply quotes. When a parameter containing spaces is passed (e.g., "test 3 file" above), the CMD shell will already have applied quotes to it. The tilde here makes sure that we don't double-quote parameters containing spaces.

Dealing with quotes in Windows batch scripts

In a Windows batch file, when you do the following:
set myvar="c:\my music & videos"
the variable myvar is stored with the quotes included. Honestly I find that very stupid. The quotes are just to tell where the string begins and ends, not to be stored as part of the value itself.
How can I prevent this from happening?
Thanks.
set "myvar=c:\my music & videos"
Notice the quotes start before myvar. It's actually that simple.
Side note: myvar can't be echoed afterwards unless it's wrapped in quotes because & will be read as a command separator, but it'll still work as a path.
http://ss64.com/nt/set.html under "Variable names can include Spaces"
This is the correct way to do it:
set "myvar=c:\my music & videos"
The quotes will not be included in the variable value.
It depends on how you want to use the variable. If you just want to use the value of the variable without the quotes you can use either delayed expansion and string substitution, or the for command:
#echo OFF
SETLOCAL enabledelayedexpansion
set myvar="C:\my music & videos"
As andynormancx states, the quotes are needed since the string contains the &. Or you can escape it with the ^, but I think the quotes are a little cleaner.
If you use delayed expansion with string substitution, you get the value of the variable without the quotes:
#echo !myvar:"=!
>>> C:\my music & videos
You can also use the for command:
for /f "tokens=* delims=" %%P in (%myvar%) do (
#echo %%P
)
>>> C:\my music & videos
However, if you want to use the variable in a command, you must use the quoted value or enclose the value of the variable in quotes:
Using string substitution and delayed expansion to use value of the variable without quotes, but use the variable in a command:
#echo OFF
SETLOCAL enabledelayedexpansion
set myvar="C:\my music & videos"
md %myvar%
#echo !myvar:"=! created.
Using the for command to use the value of the variable without quotes, but you'll have to surround the variable with quotes when using it in commands:
#echo OFF
set myvar="C:\my music & videos"
for /f "tokens=* delims=" %%P in (%myvar%) do (
md "%%P"
#echo %%P created.
)
Long story short, there's really no clean way to use a path or filename that contains embedded spaces and/or &s in a batch file.
Use jscript.
Many moons ago (i.e. about 8 years give or take) I was working on a large C++/VB6 project, and I had various bits of Batch Script to do parts of the build.
Then someone pointed me at the Joel Test, I was particularly enamoured of point 2, and set about bringing all my little build scripts into one single build script . . .
and it nearly broke my heart, getting all those little scripts working together, on different machines, with slightly different setups, ye Gods it was dreadful - particularly setting variables and parameter passing. It was really brittle, the slightest thing would break it and require 30 minutes of tweaking to get going again.
Eventually - I can be stubborn me - I chucked the whole lot in and in about a day re-wrote it all in JavaScript, running it from the command prompt with CScript.
I haven't looked back. Although these days it's MSBuild and Cruise Control, if I need to do something even slightly involved with a batch script, I use jscript.
The Windows command interpreter allows you to use the quotes around the entire set command (valid in every version of windows NT from NT 4.0 to Windows 2012 R2)
Your script should just be written as follows:
#echo OFF
set "myvar=C:\my music & videos"
Then you may put quotes around the variables as needed.
Working with the CMD prompt can seem esoteric at times, but the command interpreter actually behaves pretty solidly in obeying it's internal logic, you just need to re-think things.
In fact, the set command does not require you to use quotes at all, but both the way you are doing your variable assignment and the way the ,method of using no quotes can cause you to have extra spaces around your variable which are hard to notice when debugging your script.
e.g. Both of the below are technically Valid, but you can have trailing spaces, so it's not a good practice:
set myvar=some text
set myvar="some text"
e.g. Both of the below are good methods for setting variables in Windows Command interpreter, however the double quote method is superior:
set "myvar=Some text"
(set myvar=Some value)
Both of these leave nothing to interpretation the variable will have exactly the data you are looking for.
strong text However, for your purposes, only the quoted method will work validly because you are using a reserved character
Thus, you would use:
set "myvar=c:\my music & videos"
However, even though the variable IS correctly set to this string, when you ECHO the sting the command interpreter will interpret the ampersand as the keyword to indicate another statement follows.
SO if you want to echo the string from the variable the CMD interpreter still needs to be told it's a text string, or if you do not want the quotes to show you have to do one of the following:
echo the variable WITH Quotes:
Echo."%myvar%"
echo the variable WITHOUT Quotes:
Echo.%myvar:&=^&%
<nul SET /P="%myvar%"
In the above two scenarios you can echo the string with no quotes just fine. Example output below:
C:\Admin> Echo.%myvar:&=^&%
C:\my music & videos
C:\Admin> <nul SET /P="%myvar%"
C:\my music & videos
C:\Admin>
Try using the escape character '^', e.g.
set myvar=c:\my music ^& videos
You'll have you be careful when you expand myvar because the shell might not treat the & as a literal. If the above doesn't work, try inserting a caret into the string too:
set myvar=c:\my music ^^^& videos
Two solutions:
Don't use spaces or other characters that are special to the command interpreter in path names (directory or file names). If you use only letters, numbers, underscores, and hyphens (and a period before the extension to identify the file type), your scripting life will become immeasurably simpler.
I have written and otherwise collected a plethora of tools over the years, including a DOS utility that will rename files. (It began as something that just removed spaces from filenames, but morphed into something that will replace characters or strings within the filenames, even recursively.) If anyone's interested, I will get my long-neglected web site up and running and post this and others.
That said, variables aren't just for holding pathnames, so...
As others have already pointed out, SET "myvar=c:\my music & videos" is the correct workaround for such a variable value. (Yes, I said workaround. I agree that your initial inclination to just quote the value ("my music & videos") is far more intuitive, but it is what it is, as they say.

Resources