File Name Quoting

Off-topic posts of interest to the "Everything" community.
Post Reply
therube
Posts: 4955
Joined: Thu Sep 03, 2009 6:48 pm

File Name Quoting

Post by therube »

File Name Quoting

on a drag & drop, or on a SentTo,
who controls quoting?

is it Windows, Windows shell, cmd.exe or... ?

Code: Select all

1. C:\TMP\BRU\red_blue.avi
2. C:\TMP\BRU\red_blue - eggo - -^=^33.avi
3. C:\TMP\BRU\red_blue-^=^33.avi
drag&drop or SendTo to go.bat:

Code: Select all

1. C:\TMP\BRU\red_blue.avi
2. "C:\TMP\BRU\red_blue - eggo - -^=^33.avi"
3. C:\TMP\BRU\red_blue-=33.avi
-

1. is straight forward, is not quoted
2. contains spaces, so is quoted
3. is "straight forward", is not quoted - BUT is not parsed correctly - the ^'s cause issues

-

if all were quoted, there wouldn't be any issues
how do you get all quoted, or how do you have (cmd.exe, a batch file) to not mangle things up when seeing
"illegal" characters (like, ^) - in a "simple" manner ?

hmmm... well, you can escape the ^, so ^^, so C:\TMP\BRU\red_blue-^^=^^33.avi
but that's not particularly feasible... ?
void
Developer
Posts: 16680
Joined: Fri Oct 16, 2009 11:31 pm

Re: File Name Quoting

Post by void »

Quoting is handled by the shell.
Drag & drop is badly implemented for batch files.
The names are quoted, if a space is present, but not if a special character is found, like &,;^

For spaces only in your filenames, you need to change your code only a bit.

@ECHO OFF
ECHO "%~1"
COPY "%~1" "%CD%\test\" /Y /S
MOVE "%CD%\mob\*.png" "%CD%\test\test.png"
7za u -tzip "%appdata%\.virto\pack.zip" "test" -r

%~1 expands always to an unquoted version, so can always quote them in a safe way.

"c:\Docs and sets" -> %~1 -> c:\Docs and sets -> "%~1" -> "c:\Docs and sets"
c:\Programs -> %~1 -> c:\Programs -> "%~1" -> "c:\Programs"

For more details read Drag and drop batch file for multiple files?
https://stackoverflow.com/a/14787643



A work around:


Dealing with %1, shift or %* could fail with drag&drop, because the explorer is not very smart, when it creates the command line.

Files like Cool&stuff.cue are not quoted by the explorer so you get a cmdline like
pcutmp3.bat Cool&stuff.cue

So in %1 is only Cool even in %* is only Cool, but after the pcutmp3.bat ends, cmd.exe tries to execute a stuff.cue.

To handle with this stuff you could use this, it catch all filenames by using the cmdcmdline variable.

Code: Select all

@echo off
setlocal DisableDelayedExpansion
set index=0
setlocal EnableDelayedExpansion

rem *** Take the cmd-line, remove all until the first parameter
rem *** Copy cmdcmdline without any modifications, as cmdcmdline has some strange behaviour
set "params=!cmdcmdline!"
set "params=!params:~0,-1!"
set "params=!params:*" =!"
echo params: !params!
rem Split the parameters on spaces but respect the quotes
for %%G IN (!params!) do (
    for %%# in (!index!) do (
        endlocal
        set /a index+=1
        set "item_%%#=%%~G"
        setlocal EnableDelayedExpansion
    )
)

set /a max=index-1

rem list the parameters
for /L %%n in (0,1,!max!) DO (
  echo %%n #!item_%%n!#
)
pause

REM ** The exit is important, so the cmd.exe doesn't try to execute commands after ampersands
exit
Btw. there is a line limit for drag&drop operations of ~2048 characters, in spite of the "standard" batch line limit of 8191 characters.
https://stackoverflow.com/a/5192427/463115
therube
Posts: 4955
Joined: Thu Sep 03, 2009 6:48 pm

Re: File Name Quoting

Post by therube »

Seems I never posted what "go.bat" was (even though I knew what it was).

go.bat:

Code: Select all

@echo off
echo %*
pause

Dang ^, yep caret's (not carrots).
If SendTo (or Drag & Drop) didn't eat caret's, life would be much easier ;-).
therube
Posts: 4955
Joined: Thu Sep 03, 2009 6:48 pm

Re: File Name Quoting

Post by therube »

The names are quoted, if a space is present, but not if a special character is found, like &,;^
I'm not quite sure if that is clear or if I'm misunderstanding...
if a space is present
That is pertinent.


And I'll note that similar happens with a closing-paren, ")" with a batch file as below:
(An opening-paren, "(", is immaterial.)

go.bat:

Code: Select all

	for %%i in (%*) do echo %%~i

Code: Select all

	  bad:		   ok:

	x(1).mpg	x(1) .mpg
	x(2).mpg	x(2.mpg
	x(3).mpg	x (3)testing123.mpg
And with that, I've been running the same batch file for 8 years now, & you mean to tell me that I've never used a data set like:
x(1).mpg x(2).mpg x(3).mpg...
I find that rather hard to believe.


In Everything, how do you find files that have a ')', but no <sp> in the filename?
(I came up with a number of machinations, but none were "right". Close, but not right.)

^(?!\s+$).+
& then I guess ^(?!\s+$).+\) finishes it (which I guess says "no spaces, but with a closing-paren").


One day, I ought to try to understand these lookaheads & lookbacks.
One day, I ought to try to understand batch files ;-).
NotNull
Posts: 5458
Joined: Wed May 24, 2017 9:22 pm

Re: File Name Quoting

Post by NotNull »

therube wrote: Fri Oct 14, 2022 7:51 pm In Everything, how do you find files that have a ')', but no <sp> in the filename?
Does this get the desire results?

Code: Select all

)  !" "
therube
Posts: 4955
Joined: Thu Sep 03, 2009 6:48 pm

Re: File Name Quoting

Post by therube »

By George, I think you've got it.

(What I came up with, above, is not correct.)
Which is because I didn't understand the subject line, what they were trying to accomplish: "Regex - Match String That Does Not Contain Only Spaces".


Heh. So when did ! become a NOT?
NotNull
Posts: 5458
Joined: Wed May 24, 2017 9:22 pm

Re: File Name Quoting

Post by NotNull »

therube wrote: Fri Oct 14, 2022 8:14 pm Heh. So when did ! become a NOT?
it has been this way ever since I stertad using Everything (in 2017).
(I should ask you; you're the veteran here :) )
therube
Posts: 4955
Joined: Thu Sep 03, 2009 6:48 pm

Re: File Name Quoting

Post by therube »

! == NOT
NOT sure where my brain is today, but it's probably tied up in a knot!
NotNull
Posts: 5458
Joined: Wed May 24, 2017 9:22 pm

Re: File Name Quoting

Post by NotNull »

:lol: :lol:
therube
Posts: 4955
Joined: Thu Sep 03, 2009 6:48 pm

Re: File Name Quoting

Post by therube »

So I took the above & have been using this batch file for a while now.

XXhash64.BAT:

Code: Select all

@echo off
rem   "carot.bat" (heh) "carat.bat"
rem   SjB 10-3-2022
rem   cause
rem   a filename, with a ^ (carat), but NOT followed by a <sp> (somewhere in the filename)
rem   is NOT parsed correctly
rem   when used with a 'SendTo' or a 'drag & drop'
rem   file names such as: "x^x" or "x^x.txt", FAIL, where "x^ x x" (contains spaces) or "x^ - test 123.TXT" are just fine
rem   probably - ONLY with batch files (using %* or %1...), where doing the same directly to a .exe is not an issue
rem
rem   go.bat (drag & drop files to go.bat & observe results):
rem   		@echo off
rem   		echo %*
rem   		pause
rem
rem   work-around, per void, per xxx, noted up, VERY ROUGHLY, & NOT understood very well - by me ;-)



@echo off
:: do note that originally, when i was echoing, /I/ used parms, where /he/ used params
:: and that is why, at first, i was getting NOTHING echoed back with my PARMS  (dumy!)
:: and to confuse things more, i've not kept both my PARMS & his params ;-)

:: in my comments below, "BOTH" or "2"... all depend on how many files were sent to carot.bat
:: & whether they contained spaced or not...


setlocal DisableDelayedExpansion
set index=0
setlocal EnableDelayedExpansion

rem *** Take the cmd-line, remove all until the first parameter
rem *** Copy cmdcmdline without any modifications, as cmdcmdline has some strange behaviour

set "params=!cmdcmdline!"

rem   echo parms: %params%
rem   echo parms: !params!
rem   echo cmd  : !cmdcmdline!
rem   echo.
rem   echo ...........cmd is the FULL command line, incl. cmd.exe /c itself...
rem   :: so %cmdcmdline% == e:/.../cmd.exe == %ComSpec%
rem   :: but how/why does !cmdcmdline! get resolved to "everything"?
rem   pause

set "params=!params:~0,-1!"
rem   echo.
rem   echo parms01: %params%
rem   echo parms01: !params:~0,-1!
rem   echo ...........not sure what is going on here?
rem   echo ...........in this case parms01 /IS/ being set (and can be read back - SANS the closing ")
rem   echo ...........and what, ~0 is the full command line?
rem   echo ...........as is ~0,-1? (where ~0,1 would be the first parameter, or something ?)
rem   echo ...........ah no! that says ~0, the full command line /MINUS/ the final character (the closing ")
rem   echo ...........and ~0,-2 would be the full command line /MINUS/ the final 2 characters - so similar to a seg$(len-1)
rem   pause

set "params=!params:*" =!"
rem   echo.
rem   echo parms02: %params%
rem   echo parms02: !params:*" =!
rem   echo ...........shows the 2ND filenmame, but not the first - not sure why?
rem   echo ...........but if there were 2 non-quoted files, they do both display here?
rem   echo ...........oh, and PARMS02 contains the "bastardized", wrong name, where params... contains the "correct" names
rem   echo ...........maybe, params... contains only the "non-quoted" parameters?
rem   pause

rem   echo.
rem   echo params: !params!
rem   echo.
rem   echo ...........now, why do BOTH names show up here?
rem   pause

rem   echo.
rem   echo parms03: %params%
rem   echo.
rem   echo ...........at this point, PARMS03 is the same as params
rem   pause

rem   xxh %params%
rem   echo.
rem   echo ...........so, NO, this does not work, cause as soon as you use PARMS03, it again gets bastardized
rem   pause
rem   echo.

rem Split the parameters on spaces but respect the quotes
for %%G IN (!params!) do (
    for %%# in (!index!) do (
        endlocal
        set /a index+=1
        set "item_%%#=%%~G"
        setlocal EnableDelayedExpansion
    )
)
rem   :: so... !index! is incremented for each filename passed (initially set to 0)

set /a max=index-1
rem   :: makes the max (math) correct

rem list the parameters
for /L %%n in (0,1,!max!) DO (
  xxh  "!item_%%n!"
)
rem   :: oh, so item_%%n, where %n is an index (array) number, holds the passed filenames from %G
rem   :: so is this a "round-about" way, or a "robust" way to do things?
rem   :: could you just combine the %G parts with xxh.exe %G, or does the "expansion" play in?
echo Done!
pause

REM ** The exit is important, so the cmd.exe doesn't try to execute commands after ampersands
exit


Dealing with %1, shift or %* could fail with drag&drop, because the explorer is not very smart, when it creates the command line.

Files like Cool&stuff.cue are not quoted by the explorer so you get a cmdline like
pcutmp3.bat Cool&stuff.cue

So in %1 is only Cool even in %* is only Cool, but after the pcutmp3.bat ends, cmd.exe tries to execute a stuff.cue.

To handle with this stuff you could use this, it catch all filenames by using the cmdcmdline variable.

Btw. there is a line limit for drag&drop operations of ~2048 characters, in spite of the "standard" batch line limit of 8191 characters.
Not a big deal, but (at least with what I've got above), you cannot run XXhash64.BAT from a command-line itself?
You can SendTo, you can drop a file(s) onto the .bat, but you can't XXhash64.BAT <filename>?

You can also:

Code: Select all

echo   abc | XXhash64
or
dir /b abc | XXhash64
& you do get a hash, but you're getting a of a data stream (STDIN), rather then a file named "abc".

If I try to:

XXhash64.BAT xxhash64.bat

I get:

Code: Select all

C:\BIN>xxhash64.bat xxhash64.bat
Error: Could not open 'E:\Windows\system32\cmd.ex': No such file or directory.
Done
Press any key to continue . . .
Note cmd.ex vs cmd.exe ?
Post Reply