I am writing a script to zip up old files, using forfiles for the looping and 7za for the zipping. I have been struggling with how to deal with spaces in the filenames, and although I have found a solution that seems to work, not understanding why has me nervous about deploying it to production.
Here is the command that appears to work:
forfiles -p%rootLogDir% -s -m*.log -d-14 -c"cmd /c 7za a -tzip """@PATH\@FILE-%date%.zip""" """@PATH\@FILE""""
Note that the path and filename arguments to 7za have 3 (yes THREE) sets of quotes around them. One set of quotes does nothing, two sets of quotes resulted in the script adding every file in the directory into the archive, rather than the one specified, and three appears to work.
Can anyone explain why so many are required? I would have thought that after one set the rest are superfluous, but apparently I am wrong.
( forfiles
is a cmd.exe subcommand? If so, you should re-tag your question with one of the many (MS)windows tags available. )
Quoting can be a maddening experience, even for people with much experience in shell and bat scripts.
@BugFinder's msg is appropriate, and I would add that 3 dbl-quotes is one way to "quote" a single double-quote char.
You are working 'with' the command processor (cmd.exe?). You type a command (with 1 or more words or operators), i.e.
myCommand /s /d %dir% file1 file2 > sumFile
and then press the enter key. The command processor doesn't just start executing the command you have submitted, it scans the line, looking for special case words and symbols, like variable names. In Unix shells environment variables look like $varName
or ${varName}
. In .bat files %var%
or %%v%%
. That variable has to be converted into a value.
That is just one pass that the command processor makes, there are others. But for your needs, the cmd-processor is scanning for word sets that should be taken as one word. If you have a var="one two"
, not surrounding the value side with quotes will confuse any command that has to process it. it will look like var=one .... two
(separate word, right?).
So if for some reason you need to pass thru a double-quote char to a lower layer of processing, you have to follow the command processor rules, quote things as needed and then everything will work ok.
Just as "word" is a quoted word, """
is a quoted double quote. After the command processor does it normal processing of quotes, the middle double quote will still be remaining in the command processor's 'view' of what is on the command line (after variable have been expanded, and all the other order of processing rules have been followed.)
Whew!
So to wrap it up, you wrote in a comment
But then
"""
->""
->"
,
No, """
=> "
so why is one quote not sufficient?
Because using """
is one way to have the command processor leave a stand-alone double quote char remain on the command line and not blow up.
Or does the first condensed double quote gain some sort of magical power?
No magical powers, note that your command has a later """
s. Each set is leaving 1 "
char for later processing.
As @BugFinder points out, \"
might be sufficient, but I'm not sure which command processor or shell you are using, so I can't run a test.