Proper way of getting function arguments with spaces and specials characters...

Discussion forum for all Windows batch related topics.

Moderator: DosItHelp

Post Reply
Message
Author
Gilcio
Posts: 2
Joined: 07 Oct 2020 13:32

Proper way of getting function arguments with spaces and specials characters...

#1 Post by Gilcio » 07 Oct 2020 14:54

Hi guys!
First time here, but dealing with batch codes from a long time.
I'd like to get some help developing a proper way to get correct parameters in a batch function.
In some functions, I usually need to get the parameters the way they are really passed, not "eating" any comma and not getting the script broked by any special characters.
If the function has one parameter only, it's easy and everything is there in %* the way it should.
But I usually I need to get some auxiliary paramters like variables or paths first and, so, I set the argument that might have some special stuff to the last position.
This is the only way I've found to use and treat complex arguments. But implementing this is always a trouble.
When I thought that I've found a best way by using FOR /F and tokens with *, I got problems when the first arguments (like paths) have spaces (or any other delimiter) because quotes are ignored then.
The only way I can achieve what I want by now is getting each numbered argument and its length then subtracting from all arguments, getting then the "rest argument" that I want, but that is some kind expensive, because I have to call String Len code many times.
Is there a way to use FOR /F delimiting by space but respecting quoted parameters with spaces?
Or anyone else knows a better and proper way of achieving what I want?!

Here's some code to illustrate the problem:

Code: Select all

@ECHO OFF
:: When no space in first arguments everything works
CALL :MyFunc arg1 argument2 c:\path\to\arg3 c:\path\toarg4 ,run, anything "here" even specials "&" like "|<>" and single" quotes
:: But spaces broke first arguments
CALL :MyFunc arg1 "argument 2" c:\path\to\arg3 "c:\spaced path\to arg4" ,run, anything "here" even specials "&" like "|<>" and single" quotes
GOTO :EOF

:MyFunc
SETLOCAL EnableDelayedExpansion
ECHO Checking if everything is there
ECHO %*
ECHO.
SET params=%*
ECHO Traditional way of parsing parameters works for first params:
ECHO 1:%1 2:%2 3:%3 4:%4 
ECHO But how to get rest this way?
ECHO.
ECHO Trying to get through FOR /F and tokens with * to get rest
FOR /F "tokens=1,2,3,4*" %%a IN ("!params!") DO SET "arg1=%%~a" & SET "arg2=%%~b" & SET "arg3=%%c" & SET "arg4=%%~d" & SET "argrest=%%e"
ECHO It will work for non spaced first params but not for parameters with spaces quoted because delims is space
ECHO Parsing Desired Arguments With FOR: 
ECHO 1:!arg1! 2:!arg2! 3:!arg3! 4:!arg4! Rest:!argrest!
ECHO.
GOTO :EOF
Thank you so much!

penpen
Expert
Posts: 2009
Joined: 23 Jun 2013 06:15
Location: Germany

Re: Proper way of getting function arguments with spaces and specials characters...

#2 Post by penpen » 08 Oct 2020 03:51

If you are want to pass such strings within your script, then just don't pass those strings, but environment variables with such a value instead (untested):

Code: Select all

@echo off
setlocal enableExtensions disableDelayedExpansion
set "variable=,&!|"
call :test variable
goto :eof

:test
setlocal enableDelayedExpansion
echo(!variable!
endlocal
goto :eof

If the string are passed externally from your batch then the following thread might help you:
viewtopic.php?f=3&t=2836

penpen

Gilcio
Posts: 2
Joined: 07 Oct 2020 13:32

Re: Proper way of getting function arguments with spaces and specials characters...

#3 Post by Gilcio » 08 Oct 2020 19:05

Thanks for answering.
Passing by reference instead value is the best and simplest way indeed. Other ways is usually too much expensive and they will spend more process time treating parameters than the main function purpose.
I just was hoping for the existence of some magic trick unknown by me to achieve that, lol, because the FOR /F approach was too close to what I needed, handling * in a pretty good way but for the first tokens is impossible to get them split like default batch parameters passing functionality.
Thanks again.

pieh-ejdsch
Posts: 240
Joined: 04 Mar 2014 11:14
Location: germany

Re: Proper way of getting function arguments with spaces and specials characters...

#4 Post by pieh-ejdsch » 18 Oct 2020 05:19

maybe you can try it.

Code: Select all

:argsNtoTokens
@echo off
for /f "delims==" %%a in ('2^>nul set param_') do set "%%a="
if ! lss ' (setlocal disabledelayedexpansion) else setlocal
@set prompt=$g$s
:::::::::::::::::::: setting ::::::::::::::::::::::::::::::::::
 rem use comma or space as delimiter: set argsN=2,3,5,*  (OR 1,3,6,*  OR 2 3)
 rem use preset option in batch OR use The preset in the ARGSNCMD environment variable.
if NOT defined argsNcmd ( set argsN=1
) else set argsN=%argsNcmd%
:::::::::::::::::::: END settings :::::::::::::::::::::::::::::
 rem NOTE this file does NOT contain a help like /? -Help ...
 rem so that this batch works as intended
if : == so * what can i do & (
ToParameters such as options or arguments, e.g. Token in a for loop.
The entire parameter line is read in.
Only spaces and quotation marks are treated to delimit the parameters.
Escaped quotation marks are not supported.
Unless they are summarized in the last token.
The variable argsNcmd can be used to set the selection of parameters.
All variables that begin with PARAM_ are deleted so that they can be
used as selected at the end.
Within this batch:
Quotation marks are included in the variable so that the forLoop recognizes
the variable as a string and not as a file.
Is also required to insert the line break into the variable.
In the for /f loop, all parameters/ are output line by line.
So the batch runs without goto.
)
( set \n=^^^
%= The empty line 2 is critical - DO NOT REMOVE =%
)
set /a argN=1
if "%argsN%" equ "*" set "argN=*"
set param_*=%*
set param_=1
if ' lss ! setlocal enabledelayedexpansion
set drag="" !param_*! ""
set "drag=!drag: "=%\n%
 "!"
for /f eol^=^:tokens^=1-2delims^=^" %%g in (!drag:" ="%\n%
!) do ( if ! lss ' endlocal
 set withoutQ="%%g"
 set "isQuoted=%%h"
 if NOT defined isQuoted (set "Quote=") else set "Quote=""
 setlocal enabledelayedexpansion
 for /f eol^=^:delims^=^" %%i in ("!isQuoted!"!withoutQ:^ ^=%\n%
!) do ( if ' lss ! setlocal enabledelayedexpansion
  for /f "tokens=1*" %%P in (". !Quote!") do (
   set "param_*=!param_*:*%%Q =!"
   for /f "tokens=1* delims=, " %%j in ("!argsN!") do (
    for /f "tokens=1*" %%l in ("!argN! !param_*!") do (
     if ! lss ' endlocal
     if %%j equ * set "*=1"
     if %%l neq * ( set /a argN += 1
      if NOT defined * set "param_*=%%m"
     )
     if %%j equ %%l if %%j neq * ( if NOT defined isQuoted (
       set param_%%j=%%i
      ) else set param_%%j="%%i"
       rem param_N: %%i
      set "argsN=%%k"
     )
    )
   )
  )
 )
)
for /f "tokens=*delims=" %%a in ('2^>nul set param_') do (
 if defined param_ endlocal
 if "%%a" neq "param_=1" set "%%a"
)
 rem set par
exit /b

Post Reply