0

Before you go marking this as a duplicate hear me out

My question;

A: has different requirements than all the others (which are basically "whats an escape character?") Including: not having to use an external file to enter in parameters to functions

B: questions the existence of this mess rather than accepting 'no' or 'its complicated' as the answer

C: understands that there are escape characters that already exist and ways to work around that

D: comes from a different skill level and isn't a 2-7 years old question

E: requires the use of quotes rather than something like [ because quotes are the only thing that works with spaced strings

Also before ya'll say I didn't try stuff I read these (all of it including comments and such):

Batch character escaping

http://www.robvanderwoude.com/escapechars.php

https://blogs.msdn.microsoft.com/oldnewthing/20091029-00/?p=16213

using batch echo with special characters

Escape angle brackets in a Windows command prompt

Pass, escape and recognize Special Character in Windows Batch File

I didn't understand that all fully, because to fully understand all that I'd have to be much better at batch but here is what I gleaned:

So I understand theres a whole table of escape sequences, that ^ is the most used one, that you can use Delayed Expansion to do this task so that the characters don't get parsed immediately, just 'expanded' at runtime, but then that the Enable Delayed expansion thing doesn't always work because with pipe characters, the other files/things being piped to/from don't inherit the expansion status so

A: you have to enable it there too

B: that forces you to use that expansion

C: it requires multiple escape characters for each parsing pass of the CLI which apparently is hard to determine and ugly to look at.

This all seems rather ridiculous, why wasn't there some sort of creation to set a string of odd inputs to literal rather than process the characters. Why wasn't it just a simple flag upon some super duper special character (think alt character) that would almost never appear unless you set the font to wingdings. Why does each parsing pass of pipe characters remove the escape characters? That just makes everything insane because the user now has to know how many times that string is used. Why hasn't a tool been developed to auto scan through odd inputs and auto escape them? We have a table of the rules, is it really that hard? Has it been done already? What would it require that's 'hard'?

Down the rabbit hole we go

How did I get here you ask? Well it all started when I made a simple trimming function and happened upon one of the biggest problems in batch, escaping characters when receiving inputs. The problem is alot of my inputs to my trimming function had quotes. Quotes are escaped by using "" in place of " so something like

::SETUP
::parenthesis is just to deliniate where it goes, it isn't 
::actually in 
::the code
set "var=(stuff goes here)"
call :TrimFunc "%var%",var

:TrimFunc
::the + are just to display the spacing otherwise I can't tell
echo beginning param1 is +%~1+
::code goes here for func
gotoEOF

::END SETUP

::NOTE the + characters aren't part of the actual value, just the 
::display when I run this function

set "var=""a"""

::got +"a"+

will work but

set "var="a " 

::got +"a+

::expected +"a +

set "var="a ""

::got +"a+

::expected +"a "+

set "var="a " "

::got +"a+

::expected +"a " +

set "var="a"

::got +"a",var+

::expected +"a+

will not work as expected. oddly,

set "var="a""

::got +"a"+

seemes to work despite not being escaped fully. Adding any spaces seems to disrupt this edge case.

Oddly enough I've tried doing:

set 'var="a"'

::got ++

::expected +"a"+

But I have no idea what changing ' to " actually does when its the one that contains the argument (not the ones that are supposed to be literal).

To see what would happen and

What I want:

Surely there must be some sort of universal escape character thing such that I can do this (assume the special character was *)

set *var=""something " "" " """*
call :TrimFunc "%var%",var
echo +%~1+

would net me

+""something " "" " """+

with no problems. In fact, why can't I have some universal escape character that can just be used to take in all the other characters inside it literally instead of the command line trying to process them? Perhaps I'm thinking about this wrong but this seems to be a recurring problem with weird inputs all over. I just want my vairbales, pipes and strings and all that to just STAY LITERAL WHEN THEY'RE SUPPOSED TO. I just want a way to have any input and not have any weird output, it should just treat everything literally untill I want it not to because it was enclosed by the mystical super special character that I just invented in my mind.

::noob rant

I don't see why this was never a thing. Whats preventing the makers of this highly useful language from simply creating a flag and some character that is never used to be the supremo escape character. Why do we need like 10 different ways of escaping characters? I should be able to programatically escape inputs if necessary, it should NEVER be the users job to escape their inputs, thats absolutely ridiculous and probably a violation of every good coding standard in existence

::END noob rant

Anyways. I'd be happy to be enlightened as to why the above is or isn't a thing. I just want to be able to use quotes IN A STRING (kinda important) And I can't comprehend why its not as simple as having one giant "treat these things as literals" flag that ALWAYS JUST WORKS(tm).

By the way, In case you're wondering why my function takes in the name of the variable it's writing to, I couldn't figure out how to get labels inside labels working without using delayed expansion. Using that means the variable I'm making is local not global so I use the name of the global variable to basically set it (using it's name) to the local value on return like this:

endlocal & set "%~2=%String%"

Feel free to yell at me on various things because I am 99% certain I'm doing something horribly syntactically wrong, have some bad misunderstandings or am simply way to naive to truly understand the complexity of this problem but to me it seems amazingly superfluous.

Why can't the last quote be used like the special character it is but any preceeding ones are taken literally (maybe depending upon a flag)

for example

set "var="a ""

why doesn't the ending two quotes act specially and the ones in between act literally? Can the CLI not tell where the line ends? Can it not tell the difference between the first and last quotes and the ones in between? This seems simple to implement to me.

As long as I can echo things properly and save their literal value from parameter to variable I'm happy.

Community
  • 1
  • 1
Redacted
  • 613
  • 6
  • 23
  • 1
    I commend you for the wealth of information, so I have to ask if you have read, [How do I ask a good question?](https://stackoverflow.com/help/how-to-ask) and [How to create a Minimal, Complete, and Verifiable example](https://stackoverflow.com/help/mcve) – Squashman Oct 16 '18 at 15:45
  • Yes, thats why I provided an MCVE by setting a variable, making it a parameter, echoing it inside the function and saying what it displays and what I want it to display instead given the requirements I specified (no external files, not using the traditional methods, something programmatic) – Redacted Oct 16 '18 at 15:47
  • 2
    just to send you to the ancient secret cellars of your rabbit hole: [related](https://stackoverflow.com/questions/4094699/how-does-the-windows-command-interpreter-cmd-exe-parse-scripts) – Stephan Oct 16 '18 at 15:51
  • Appreciate the link: apparently this is part of the problem: "If it is a quote ("), toggle the quote flag. If the quote flag is active, then only " and are special. All other characters lose their special meaning until the next quote toggles the quote flag off. It is not possible to escape the closing quote. All quoted characters are always within the same token.". thus the mess is a problem with the implementation. I don't know WHY they'd make it a toggle implementation but whatever – Redacted Oct 16 '18 at 15:59
  • maybe it looked like a good idea forty years ago... `cmd` isn't "modern" in any context. You may want to switch to Powershell, which is a designed language with much more functionality. – Stephan Oct 16 '18 at 16:47
  • Its a work related thing so I can't just switch. Also, despite its nasty quirks its still quite useful, I just want a way around some of the quirks. I always find it odd how great some parts of languages are and other parts just make no sense. Maybe the wrong guy was put in charge of that part or something or they didn't think ahead to the use cases in the future – Redacted Oct 16 '18 at 16:49
  • Oh, yeah, the answer to "why is batch like this?" is almost always "backwards compatibility reasons." – SomethingDark Oct 16 '18 at 19:02
  • I think implementing a simple flag should be do-able by punchcards, much less a fully fledged home computer with a UI. There is no way a toggle implementation is the only backwards compatible way to do flags. Not trying to be all pythonic but they really shoulda just had 'one good way of doing it' for escape characters. That shoulda been part of the initial design. Maybe its hard/was hard but to me it seems rather easy, even with basic languages. If anyone would like to educate me on why its not easy, I'd be happy to listen – Redacted Oct 16 '18 at 19:08

1 Answers1

0

Firstly, I'm don't really understand why you will want to use set "var=something" instead of set var=something, it doesn't seems to have difference.

Secondly, hope that helps, which I have (recently? IDK.) invented a method to deal with the annoying quotes. Hope this batch inspires or helps you to do sth similar.

@echo off
title check for length of string
color de
mode con: cols=90 lines=25
goto t

:t
set str=error
set /p str=Please enter four characters: 
set len=0
goto sl

:sl
call set this=%%str:~%len%%%
if not "%this%" == "" (set /a len+=1 & rem debug" == "" (set /a len+=1
goto sl)
if not "%len%" == "4" (set n= not) else (set n=)
echo This is%n% a four character string.
pause >nul
exit

Which in your case:

if not "%var%" == "" (call :TrimFunc "%var%",var & rem debug" == "" (call :TrimFunc "%var%,var)
) 

Hope that helps. Add oil~ (My computer doesn't support delayexpansion with unknown reason. Therefore, most of the codes are a bit clumsy.)


P.S.: If you are simply removing text and not replacing text, why not use set var=%var:string=%? If the string required is a variable too, then you can try this: call set var=%%var:%string%=%%

  • 2
    I will help you understand the the quoting of the `SET` argument. What if the string you needed assigned was `Some&Thing`. This will not work: `set var=Some&Thing`. But quoting the command protects special characters inside the string: `set "var=Some&Thing"` – Squashman Oct 16 '18 at 16:06
  • 3
    It's also to prevent unintended spaces (invisible in editor) or add intended spaces `set "var=string with a space at the end "` – Stephan Oct 16 '18 at 16:28