Consider .exe shims instead of .bat — the documented Git Bash setup silently loses arguments containing | & > ^
#1731
joshdaugherty
started this conversation in
Ideas
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
Suggestion: ship the
bin\shims as.exelaunchers rather than.batfiles. That would spare Git Bash and PowerShell users a mostly silent argument-corruption problem that the Git Bash setup in the docs leads into.Posting this as a discussion rather than an issue for two reasons: your
config.ymlpoints feature requests here, and the root cause is not in Herd's code. I checked that carefully and want to say so up front, so nobody goes looking for it in the shims.What users hit
The Git Bash section of the Windows docs says "If you want to use the Herd binaries in Git Bash, add these aliases to your
.bash_profile:"With that setup, an argument containing
|,&,>, or^does not reach PHP intact. Two of the four cases stop the command before PHP runs at all; the other two change the value and give no error.A|B'B' is not recognized as an internal or external commandA&B'B' is not recognized as an internal or external commandA>BBis created in the current folderA^BABWhere the problem actually is
A
.batfile can only be run bycmd.exe, so Git Bash startscmd.exe /cto run it. When Git Bash builds that command line, it does not quote the arguments, so cmd reads these characters as its own syntax.You can see the unquoted hand-off with a
.batcontainingecho %CMDCMDLINE%. Run from Git Bash with a plain argument — plain, because with one of the four characters the command stops before it can echo anything:No quotes around
AplainB. Run the same file from cmd with quotes and all four characters come through:(
%1keeps the quotes, which is normal;%~1strips them. The point is that cmd did not treat the characters as syntax.)I ran controls to narrow it down:
%*— a.batusing%1fails the same way..batI wrote myself, with no connection to Herd, fails identically.cmd.exe— given a properly quoted command line, cmd passes all four through.A&Barrives truncated asArather than erroring.So this comes from how non-cmd shells build the command line they hand to
cmd.exe. Herd cannot fix that part.Why raise it here
Herd is where users run into it, because the Git Bash setup in the docs routes
phpthrough a.bat. Nothing on that page suggests arguments might be changed or dropped.It is also slow to diagnose. In my case:
php vendor/bin/pest tests/Feature --filter='SuiteA|SuiteB' --parallelThe
|ended the command line early, so the test run exited after 0 seconds with no output and no summary. My script looked for aTests:line, found none, and that read as "nothing to report" rather than "the command never ran". It took a few hours to find. A|in a--filteris ordinary usage.Quoting differently does not help. The argument is already correctly quoted in bash. I tried a cmd-style caret escape (
A^|B), double quotes, and a backslash escape, and all still fail.Options
.exelaunchers instead of.batfiles. An.exereceives arguments directly, with nocmd.exein between, so the problem does not arise whichever shell called it. This is the thorough fix and it covers every shim.PATH, sophp.exeresolves directly. This helps anyone calling a barephp, though not someone who has set up the documented alias, since that namesphp.batexplicitly.>and^cases produce no error and no clue, so a short warning would save the guesswork.The same applies to the other shims.
composer.batisphp "%~dp0composer.phar" %*andlaravel.batisphp "%~dp0laravel.phar" %*, so those go throughphp.battoo;expose.bat,forge.bat, andherd.batare.batfiles and take the same path through cmd.Reproducing it
Windows 11 Pro build 26200, AMD64, Herd 1.29.0, PHP 8.4.20. From Git Bash (change
php84to your installed version):That last line is the point: a real
.exealready handles all four characters today.Workaround, for anyone who finds this
Call the real
php.exeinstead of the.bat.php.batnames the binary it would have run, so the path can be read out of it:herd userewritesphp.batto point at the newly chosen version, so re-reading it on each call keeps this in step with version switches.The fallback is worth keeping.
herd usereplacesphp.batrather than editing it in place, and I managed to make that replacement fail by reading the file at the moment of a switch, which leftphp.batmissing until I put it back. That was my own doing rather than something Herd does on its own, but a fallback costs nothing.All reactions