On 05/01/2014 12:11 PM, Linda Walsh wrote: > > On linux, (and, thus on cygwin?), "#!/bin/bash -u -x -a -b -c" > is passed as 1 argument to bash. I.e. the spaces don't break things > into separate arguments on linux. Correct. So follow it through to it's logical conclusion: /bin/bash "-u -x -a -b -c" is trying to invoke bash with one GIANT short option string as argv[1]. Per getopt() parsing rules, it is as if you were trying to invoke: /bin/bash "-u" "- " "--" "-x" "- " "--" "-a" "- " "--" "-b" "- " "--" "-c" But bash does NOT have a "- " short option (that is, the short option whose name is a space character). You have formed an illegal command line, and bash is trying to tell you that. It would be nicer if bash quoted the first option it doesn't recognize (/usr/bin/bash: "- ": invalid option) rather than hoping you are smart enough to detect the trailing space meant that you were trying to pass a space as the option name (/usr/bin/bash: - : invalid option); but such is life. > > I.e. the above is valid as well -- but it was the single "-u" switch > that doesn't work. But my point remains - you WEREN'T passing a single "-u" switch, but MUST have had a trailing space on the line, and were passing "-u " which bash is dutifully trying to parse as "-u" "- " and erroring out on the "- ". However, now that I have further tested on both Linux and cygwin systems, I CAN state that you have indeed found an inconsistency between how Cygwin execve() and Linux execve() behave - so if someone is willing to write a patch to cygwin1.dll to eliminate that inconsistency, it would be nice. On Linux, execve() strips trailing space before forming the command line that gets substituted during shebang execution. Sadly, this aspect of Linux is NOT documented in the man page; I had to learn it by experimentation. Observe this Linux transcript: $ cd /tmp $ printf '#!/bin/sh -u \necho hi\n' > blah.sh $ chmod +x blah.sh $ ./blah.sh hi $ printf '#!/bin/sh -u -\necho hi\n' > blah.sh $ ./blah.sh 2>&1 |head -n1 /bin/sh: - : invalid option Note that when the shebang had "-u ", the trailing space was stripped, and bash was run with "-u"; but when it had "-u -", there was no trailing space to strip, and bash given the literal argument "-u -" dutifully choked on the attempt to parse "- " as a short option. Cygwin, on the other hand, does not (yet) strip trailing spaces when constructing the replacement command line from a shebang. Patches thoughtfully considered. Particularly true since some people use carriage returns on script files under cygwin (I personally detest the practice, but have at least patched bash to try to allow others to use it) - stripping trailing whitespace when forming the argv[1] of a shebang line would allow the shebang to do the right thing of NOT passing the carriage return to the actual command line of the interpreter, even if the script is accidentally executed from a binary mount rather than a text mount. >> Because you weren't running /bin/bash at that point in time, but >> /usr/bin/bash. Again, you snipped the relevant portion of your original > ---- > No...I was... the output at the top was from "t.sh", which had > #!/bin/bash. > > But the error message says /usr/bin/bash. Okay, now that I have tested on a Cygwin machine, I have indeed reproduced what you are seeing. When you invoke './t.sh', which has a shebang calling out '#!/bin/sh', but in a way that provokes an error, the error calls out /usr/bin/sh. That means that the execve() logic for constructing the alternative command line is passing a different argv[0] to the replacement interpreter than what you actually specified in your shebang line. On cygwin, /bin/bash and /usr/bin/bash are ALWAYS the same file (two different spellings, but the cygwin mount code treats /bin/ and /usr/bin/ as mounts to the same single Windows directory). The execve() code responsible for locating the replacement application to run is first locating "/bin/bash" as written in your shebang line, then constructing the argv[] to pass to that application - and somewhere in that process, it ends up rewriting argv[0] to match what it considers to be the canonical name. Observe this cygwin transcript: $ cygpath -w /bin/bash C:\cygwin\bin\bash $ cygpath -w /usr/bin/bash C:\cygwin\bin\bash $ cygpath -u "C:\cygwin\bin\bash" /usr/bin/bash So, although both Unix names are usable, it is as if the execve code has run your spelling through a conversion to a windows name, then converted that windows name into the argv[0] for use, rather than preserving your original argv[0]. Not the end of the world for bash (although bash DOES care about the spelling of argv[0], it is mostly on whether the basename was 'sh' or 'bash', and NOT on what directory name it detected) - but it COULD be problematic for other apps (remember the recent traffic on this list about how '/bin/gcc' failed while '/usr/bin/gcc' succeeded, all because the program used argv[0] to construct relative names to resources where /usr/bin/../share exists but /bin/../share does not exist?). So, a patch to cygwin execve() code to preserve the user's original argv[0] spelling would be appreciated. > So why doesn't a single argument work (-u?) Because you didn't pass a single argument, but left trailing space which bash tried to interpret as a second argument, and because no one has yet provided the patch for the two execve() inconsistencies that this thread has uncovered. -- Eric Blake eblake redhat com +1-919-301-3266 Libvirt virtualization library http://libvirt.org