Maximus5 / ConEmu

Customizable Windows terminal with tabs, splits, quake-style, hotkeys and more
https://conemu.github.io/
BSD 3-Clause "New" or "Revised" License
8.61k stars 574 forks source link

Incomplete command line executed when a particular combination of quotes and | is present. #889

Open gene-pavlovsky opened 8 years ago

gene-pavlovsky commented 8 years ago

http://bugs.farmanager.com/view.php?id=3322

Versions

ConEmu build: 160914 x64 Far Manager build: 3.0.0.4805 x64 OS version: Windows 7 x64

Problem description

When executing this command from Far, the entire command line is passed correctly to the command interpreter. grep external_id video_ids.txt | cut -d\" -f4 Command interpreter receives: "C:\cygwin\usr\local\bin\bashcmd.exe" /S /C "grep external_id video_ids.txt | cut -d\" -f4" - as expected.

20161006_112837_process explorer - sysinternals_ www sysinternals com alpha_gene _cr

Adding a pipe to the command results in incorrect (truncated, no trailing " character) command line passed to the command interpreter. grep external_id video_ids.txt | cut -d\" -f4 | sort -u Command interpreter receives: "C:\cygwin\usr\local\bin\bashcmd.exe" /S /C "grep external_id video_ids.txt | cut -d\" -f4 - the | sort -u" part is missing.

20161006_113347_process explorer - sysinternals_ www sysinternals com alpha_gene

Maximus5 commented 8 years ago

And why do you post this here?

gene-pavlovsky commented 8 years ago

I'm using bashcmd, a small program I wrote to be able to use bash on Far's command line. But I think that bug can also be reproduced with a simple test program. To use bashcmd, download https://dl.dropboxusercontent.com/u/49471027/far_bash_comspec.7z The instructions are in the README files inside.

This issue doesn't happen if I run the commands from a plain Far running on it's own (without ConEmu). If I understand correctly, ConEmuC somehow intercepts execution of any child subprocess, to be able to catch ConEmu options (e.g. -new_console), then runs the child process with the original command line minus the ConEmu-related options, is that right? I see there is a cmd.exe invocation involved in the chain of processes originating from Far. This cmd process receives the correct command-line, but then doesn't pass it right because of the \". Why doesn't ConEmuC run the bashcmd.exe directly, but does it via cmd.exe? When same Far is executed without ConEmu, it runs bashcmd.exe directly.

gene-pavlovsky commented 8 years ago

Bottom line. Far tries to run bashcmd.exe with a particular command-line. If that happens in standalone Far, it works and bashcmd.exe receives the correct command-line. Under ConEmu.exe, an additional cmd.exe gets in between Far and bashcmd.exe, as result bashcmd.exe doesn't receive the correct command-line because of some quoting issues (apparently, a combination of \" followed by |).

gene-pavlovsky commented 8 years ago

When the same command is run in standalone Far. No cmd.exe - no trouble. 20161006_122155_process explorer - sysinternals_ www sysinternals com alpha_gene

gene-pavlovsky commented 8 years ago

When I was working on this: https://forum.farmanager.com/viewtopic.php?f=3&t=10242 I tried many things and quickly realized that executing something involving a lot of quotes and backslashes via cmd.exe is complete torture. The only way to get the exact command line was to run the process directly and obtain the command line via Windows-specific GetCommandLine() rather than using C-standard argc/argv. That's what bashcmd.exe does. Only this way I was able to send the exact command line from Far to bash (bashcmd.sh), with all the quotes, backslashes and such intact.

Is there a reason ConEmuC uses cmd.exe rather than run the process directly? Besides this issue, there's also the inefficiency of spawning an extra process.

Maximus5 commented 8 years ago

When I execute, for example, from Far's command line (outside of ConEmu of course)

C:\tools\7z.exe a -r test.7z *.*

Far always starts cmd.exe. But you insist it doesn't. What I'm doing wrong?

gene-pavlovsky commented 8 years ago

NoCmd Just tried it, Far didn't use cmd. I've digged deep in Far sources so I know what's happening in there. If you wanna see for yourself, see execute.cpp. Far checks the command line (PartCmdLine()) according to specified ComspecCondition option, or default if none specified - by default it checks for presence of any of <>|& characters not within quotes. Your 7z command line doesn't have any of those characters, therefore Far proceeds to directly execute 7z.exe (see Execute() function). If Far finds the command line too complex (pipes, redirections etc.), it uses ComSpec to execute the command - either System.Executor.Comspec (far:config option) if set, or ComSpec env var. In my case, I've set System.Executor.Comspec to %FAR_ComSpec% which is an env var pointing to my bashcmd.exe (all of these setup details described in the README of bashcmd 7z archive I've reference in a previous comment).

gene-pavlovsky commented 8 years ago

Some curious findings.

Also, if I run this command from a Cygwin bash under ConEmu, it executes correctly without any intermediary cmd.exe.

# export BASHCMD_DEBUG=pause
# bashcmd.exe /S /C  "grep external_id video_ids.txt | cut -d\" -f4 | sort -u"
bashcmd.exe: cmdLine=`C:\cygwin\usr\local\bin\bashcmd.exe /S /C "grep external_id video_ids.txt | cut -d\" -f4 | sort -u"`

So for some reason the issue only occurs when running under Far in current console. P.S. It doesn't seem plausible to me that Far spawns this cmd.exe, since in Far my Comspec is set to C:\cygwin\usr\local\bin\bashcmd.exe. So I can only imagine ConEmuC is starting this cmd.exe for some reason.