Ruby command line quoting

I have assigned the following command to a button:
ruby.exe "C:\User Files\test.rb" {sourcepath} {allfile}

The script test.rb just prints what it receives as command line arguments.

In C:\User Files, there are two files named one one.txt and two two.txt.

I select the 2 files, press the button, and the script receives:
["C:\\User Files\" one", "one.txt two", "two.txt"]

while I was expecting:
["C:\\User Files", " one one.txt", "two two.txt"]
["C:\\User Files\\", " one one.txt", "two two.txt"]

I checked using the command line:

> cmd /c test.rb "C:\User Files\" "one one.txt" "two two.txt"
["C:\\User Files\" one", "one.txt two", "two.txt"]

> cmd /c test.rb "C:\User Files" "one one.txt" "two two.txt"
["C:\\User Files", "one one.txt", "two two.txt"]

> cmd /c test.rb "C:\User Files\\" "one one.txt" "two two.txt"
["C:\\User Files\\", "one one.txt", "two two.txt"]

I think this is a bug: since you place a trailing backslash at the end of {sourcepath}, it should be escaped (two backslashes) otherwise it is the closing quote which gets escaped.

Unless there is another of the zillion configuration options to handle this? :slightly_smiling_face:

For the moment I found this hack:
ruby.exe "C:\User Files\test.rb" {sourcepath}\ {allfile}

Try {sourcepath|noterm}

A lot of command-line tools are confused by a \" sequence at the end of an argument, due to a bug/flaw in the C-runtime command-line parsing code that many of them use, which has been left that way for decades now.

It's technically Ruby.exe misreporting the command line given to it, not Opus generating the wrong command line, but due to the library code Ruby.exe is probably using. You can usually use |noterm to avoid the issue, in any case.

There is no such rule in Windows. Backslashes in other parts of the command-line also do not need to be escaped.

It's a bug/flaw in the C-runtime code that splits arguments into argv/argc, and the way it behaves is inconsistent with itself:

2022-08-12 21-13-01 Clipboard Image

If \ was an escape character here, you would need \\ between the Moo and Cow instead of just a single \. But you don't, because it isn't. Maybe "it's only an escape character before a quote", but leads to all sorts of problems. Things should either be an escape character or not. And this isn't a rule of the OS; it's a quirk of one particular piece of code for splitting command lines into words.

Automatically adding an extra backslash before the quote would cause problems for all the software that doesn't use the C-runtime to parse the command line. (Which includes a lot of C/C++ programs, as you can get the exact command line string from Windows and parse it yourself.)


I knew there would be an option. :slightly_smiling_face:

Tell Microsoft!

That reminds me of this hilarious part of cmd /?:

If /C or /K is specified, then the remainder of the command line after
the switch is processed as a command line, where the following logic is
used to process quote (") characters:

    1.  If all of the following conditions are met, then quote characters
        on the command line are preserved:

        - no /S switch
        - exactly two quote characters
        - no special characters between the two quote characters,
          where special is one of: &<>()@^|
        - there are one or more whitespace characters between the
          two quote characters
        - the string between the two quote characters is the name
          of an executable file.

    2.  Otherwise, old behavior is to see if the first character is
        a quote character and if so, strip the leading character and
        remove the last quote character on the command line, preserving
        any text after the last quote character.

I never fully understood it.

Haha, yes, that is a classic. :smiley:

I think most of these things are cases where people didn't think about a problem at all initially, and then had to kludge in a way to work around it, without being able to design something consistent from the start. Of course, this often then creates more problems and unexpected issues, both in it and in other things, in turn.

As an aside, the reason things like {sourcepath} include the trailing backslash by default is they were designed to be used in front of other things. For example {destpath}{file} would give you the name of the selected file, but in the destination path, without needing a \ between the two. In hindsight, it probably would have been better to force people to make the \ explicit, if only to avoid problems with C-runtime command-line parsing, but I suspect the way that parsing works wasn't known when it was designed. I know I personally didn't run into that quirk until some years later. (Before I was working on Opus, and only using it, but after things like {sourcepath} were already defined... it may even date back to the Amiga version but I don't remember that far back.)