-
Notifications
You must be signed in to change notification settings - Fork 34
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
YECHO and double quotes escape with CMD #83
Comments
I guess something similar is with
neither
nothing seems to work... tried to do this with source of Lines 372 to 376 in 1ce1b7d
after:
before: Lines 423 to 430 in 1ce1b7d
after:
and the output of
last one is the main output of
so lets tripple escapes...
and finally just to be ensured...
I guess this is because some internal function is processing argument before it is to delivered to And by the way... P.S.
this is supposed:
|
Okay, seeing as we're doing long posts... This all stems from one of those "people who haven't studied UNIX are doomed to reinvent it poorly" things. In UNIX, argc/argv parsing is done by the shell process. In Windows, argc/argv parsing is done by the child process. But, who processes shell escapes? The advantage of the UNIX model is shell escapes can be used to indicate how to layout argc/argv. In Windows, the shell will process and remove escapes, thereby having no influence over argc/argv layout. I've read the Colascione post before, but note it's built on a huge contradiction: it's contending that there is a standard way to parse and layout argc/argv, while simultaneously complaining that nobody does it. And if nobody does it, it's hardly a standard. When you realize that every process is doing its own parsing, it becomes clear why there never will be a standard. The post sort of implies that CommandLineToArgvW is basically a canonical implementation, except that it's up in shell32.dll, which is not where command line programs normally operate, so it's highly unlikely to ever be used in a command line program. My guess is that it exists to support ShellExecute() where the shell needs to apply a file association and reconstruct command lines, so it already needed a fair amount of logic, and it was made available for anyone else who wanted it. With the background out of the way, let's turn back to Yori. When I started I had a fairly ideological view that I wanted these tools to interop with other Win32 command line programs. Rather than be a self-contained ecosystem like some other shells, the goal was to make something that anyone can extend, either in-proc or out-of-proc using common idioms like argc/argv. Then I made argv a YORI_STRING, which kind of undermines that goal, but the goal is still somewhat there. What this means is that the argument parser has to be fairly stupid and not emit extended information about what it did - it doesn't communicate which arguments originally had quotes, or where an argument exists within the command line, etc. It could do this fairly easily, but it can't describe the result in argc or argv. So, Yori has two argc/argv parsers: Line 327 in 1ce1b7d
Line 288 in 1ce1b7d
"C:\Program Files"\Win into "C:\Program Files\Win" because tab completion, while still remembering whether the terminating quote was there or not. This code is...fragile.
The issue here is not the first case where trying to use argc/argv is just too simplistic. One case that's always annoyed me is CMD's echo will preserve all spaces, but Yori's won't, because there's no way to describe a whole pile of spaces in argv. Quotes are another casualty. I have this nasty feeling that the "real" fix is to have a parser that communicates this information into each program's entrypoint, which looks more like the shell one than the mini one. Or perhaps, since this is process global state, the information could be recorded in a hidden place where the program can ask "did arg 5 have quotes?", or "tell me the string that starts at arg 5 and goes to the end of the command line", or "tell me the raw string that includes arg 5 to arg 7 with everything in the middle", etc., which was known to the parser when it did the decomposition. For built-in modules, I already made baby steps in this direction with Line 725 in 1ce1b7d
Somewhat related is because the shell process is decomposing everything into an extended argc/argv internally, it can also end up dropping spaces etc. But it's certainly a big can of worms, it's not specific to any particular tool, and you'll probably find quirky behavior in non-Yori tools too just because of the general situation. |
It is always a pain to deal with spaces and quotes in Windows... sometimes my head is blowing with all that quirky behavior of tools and generally understand the situation!
So |
This will be because the quote is at the end of the line, so the parser couldn't treat it as containing some future text, and just passed the quote character along instead. In the second case, the quote is followed by text so it's using that to indicate you meant " 123" (with a leading space) which is what the output is showing. Note also that echo is a builtin, so it's using the (full) shell parser, not the mini process parser. They're two implementations with two quirky behaviors. If you ran the top command with yecho.exe, it wouldn't display anything. Also, I think your second link contains a link that hints at how this is really working in CMD: In my big wall of text, I was rhetorically asking "who processes shell escapes?" on the assumption that only the shell can process shell escapes. But what this link suggests is that CMD passes along all of the escape characters, and the child process is responsible for interpreting escapes as part of its own argc/argv processing. I'm still skeptical that this really works, because it assumes the behavior of the child process, and the child process can do anything. I can change the shell to retain escape characters when invoking child programs and change all of the child programs in the Yori tree to process them...but it means a new shell process can't really operate old Yori tools since it will pass escapes that they won't consume. Maintaining compatibility between arbitrary command line generators and arbitrary command line parsers is strangely difficult. |
Actually, I misread the link. It's saying that the caret is removed "by the command-line parser in the operating system" by which it means cmd.exe, and the character is not received by the child process. That's why there's this strange behavior of using a backslash before a quote to indicate an escape to child process, and a caret is used to indicate an escape to the shell. Yuck. |
Oh sorry... now I get it: Lines 150 to 154 in 1ce1b7d
As I understand ECHO simply do not bother about arguments at all after the last - switch and simpy outputs everything it recieves from YoriLibBuildCmdlineFromArgcArgv()
So basically this means that no external Maybe this can be achieved with So |
Oh, now I get it completely! and all is absolutely fine with This is due to bultins actually operates as a function in |
And as far as I get from those articles the logic of Windows is that the user is absolutely on his own how to pass a command line, user must know what is he doing and where... so for example when you using The next step is a It is fun enough but the logic here is that you are absolutely on your own... so if you write in CMD: and therefore
Since What if
In that way CMD user have to escape all the spaces and special symbols by hand and
will work too... and nobody who has quoted arguments for And even someone wrote such thing:
It will not be affected since this is not work at all due to CMD strips all
but who actually cares in this particular scenario of manual escapation =) And since CMD and YORI shells strips out escapes by themselves before pass it to an external this little change to |
I have an idea for all that backwards compatibility stuff... So in a nutshell: Yori is not a CMD... it is not strictly build in to the system and not not obligated to provide bulletproof backwards compatibility since configured system is not limited by design to only one version of Yori. The main idea here is to pick out use cases where changes may affect previously written scripts.
So despite this to cases is very similar at all ( you have to place Yori somewhere and configure your environment to use it ) there is a difference with YPM usage... so let's assume you have no options and forced to use Yori in What if since Yori v2.0 will not replace already existing executables but for example create a UTC timestamped folder and subfolder and basically place new versions there and there will be:
As I already mentioned there is not a big deal to keep 5 megabytes Yori versions... even 100 versions of Yori is something around 1 new Powershell Core size =) So basically all that stuff is to provide default behavior with the ability to keep previous versions in place so it can be used if something goes wrong with new one. So at least with option for users to keep already working shell you may introduce script breaking changes with ease... you only have to notify users of those changes. |
I pushed a series of changes related to this. These implement the |
Perfect!!! =) I've just grab the source and will do some tests during this week... I'm compiling it now and just want to point one thing:
It's all related to |
Hello! The only noticable thing I've hit with new We have
this file only echoes the command line it got. The second file is
this file is aimed to launch The thing is
because I think there is a enough situations where command line that comes to external Yori utility should not be rebuilded and passed as it is. And by the way... with rebuilding command line scenario the parameter should become:
I mean doubling the escapes of |
I had a bug in the earlier change that treated That said, I don't think the expression will end up as one parameter by applying Visual C++'s rules. Its rules will remove all of the nonescaped quotes and use them only to indicate how to break arguments. The string Although it sounds nice to say that there are scenarios where strings should not be manipulated, note that all of these tools need to parse the command line to find command line options and items that they should consume and remove from that combined string. In this case, If others think they can do better, I'm accepting pull requests. |
Personally I don't think that I can do better... my mind is blowing when I face all this double quote stuff =) I've just finished one quite complicated 2000+ lines CMD script which use Yori utilities quite a lot in many aspects, such as working with hex binaries, searching and replacing complicated strings, a lot of file/directory operations ( copy, move, delete, backup ) and want to say one thing: It is FANTASTIC to have such a tool as Yori! It is really just fantastic to have all those utilities and be sure that my script will work on any version of Windows. Thank you very much for all this work... all this hard-hard-hard work! P.S. There few moments that I've noticed I am missing in Yori:
Anyway this is just a wishes I believe can improve Yori... and again Thank You SO MUCH for the support!!! |
In Yori environment all works perfectly:
YORI> ECHO -n -- -argument1 "value 1"
-->-argument1 value 1
this is not what we want but quite expected. Here we need to escape our
"
symbolsYORI> ECHO -n -- -argument1 ^"value 1^"
-- >-argument1 "value 1"
and all is nice and flawless...
But something weird is going on when I try to use
yecho.exe
with CMD:CMD> yecho.exe -n -- -argument1 "value 1"
-->-argument1 value 1
Nothing special... all as expected
CMD> yecho.exe -n -- -argument1 ^"value 1^"
-->-argument1 value 1
Ok... the thing here is CMD by itself handled
^"
symbols andyecho.exe
recieved-argument1 "value 1"
as in previous attempt and nothing suprisingly new here... so in theory we just need to add additional escape for^
symbol:CMD> yecho.exe -n -- -argument1 ^^^"value 1^^^"
-->-argument1 ^"value 1^"
And that is completely unxpected behavior... let's even try what is not supposed to be:
CMD> yecho.exe -n -- -argument1 ^^"value 1^^"
-->-argument1 ^"value 1^^"
And I have tried a lot of things to make
yecho.exe
work with CMD and double quotes, but nothing was successful... the only thing what's worked is such construction:CMD> yori.exe -nouser -c ECHO -n -- -argument1 ^^^"value 1^^^"
-->-argument1 "value 1"
And this is quite expected and absolutely normal...
I understand that this is quite a headache with all that double quote "magic" in Windows and CMD specially and do not expect a quick reaction... Just want to ask:
Am I missing something here? Maybe you can give an advice how to properly escape the double quotes so
yecho.exe
will work with CMD as it works in YORI?The text was updated successfully, but these errors were encountered: