mathog
mathog

Reputation: 345

mingw64 system("command") not same as "command" in shell

A program "execinput" reads input lines from stdin and stores them into a character array "buffer" and then does this:

system(buffer);

Let "command" be any valid set of programs, parameters, and bash syntax. Ideally the next two lines would give the same result (neglecting for the moment the handling of any double quotes within "command"):

command
echo "command" | execinput

That is indeed the case on a linux system running in a bash shell. However, in bash in an "Msys2 MingW 32bit" shell this happens (trailing semicolon after the 3 is intentional):

echo 1; echo 2; echo 3;
1
2
3
echo "echo 1; echo 2; echo 3;" | execinput
1 ; echo 2; echo 3;
echo "echo 1 & echo 2 & echo 3;" | execinput
1
2
3;

The "&" character is what cmd.exe uses to separate sub-commands. That last command on a linux system, either directly in bash or through system() gives:

3
1
2

In the linux bash environment all the commands come out the same, whether run directly or via system() in execinput(). In the MSYS2 environment they don't.

I believe that COMSPEC and PATH are involved somehow but having set the former like so:

 export COMSPEC="C:\progs\msys32\usr\bin\bash.exe -c "

instead of the default COMSPEC value of:

C:\Windows\system32\cmd.exe

the results still were not the same.

Can somebody please explain what is going on here, and hopefully, how to make "command" come out the same directly on a bash command line and when invoked with system()?


More info. In a bash command line in MSYS2:

echo 'set' | execinput > short.txt
echo 'bash -c "set"' | execinput > long.txt

then compare the file contents. key differences are:

  1. long.txt has 11 BASH *symbols plus DIRSTACK, EUID, GROUPS, IFS, MACHTYPE, OPTERR, OPTIND, OSTYPE, PPID, SHELLOPTS,UID.
    Short.txt does not have these.
  2. SYSTEMROOT, COMSPEC, CONTITLE, HOMEPATH, and many others are in single quotes in long.txt, no quotes in short.txt.
    The strings are otherwise the same.
  3. PWD is in fully linux/posix syntax in long.txt and has its root at the top of the MSYS2 file system. PWD is in hybrid syntax in short.txt (starts with C: then has a / delimited path) and is the full Windows path.
  4. PATH in long.txt starts with linux/posix syntax entries, root at the top of the MSYS2 file system, then followed by entries like /c/Windows/System32. Short.txt has entries which are in full Windows syntax.
  5. Long.txt has SHLVL=2, short.txt has SHLVL=1.

Upvotes: 2

Views: 2231

Answers (2)

M.M
M.M

Reputation: 141648

"Msys2 MingW 32bit" means that you open a MSYS2 Bash shell where the path is set so that gcc resolves to a mingw-w64 build targeting native Win32. The native Win32 executable has nothing to do with MSYS2 Bash; the command processor is cmd.exe. The MSYS2 shell is only a development tool.

If you open "Msys2 MSYS2" then gcc resolves to a mingw-w64 build targeting the MSYS2 system. You can check the target with gcc -v and it will say Target: x86_64-pc-msys or similar. I tested this and it did use /usr/bin/bash as the command processor as expected.

Note that the different targets use different gcc installations; the MSYS2 target is pacman -S msys2/gcc and the native Win32 target is pacman -S mingw32/mingw-w64-i686-gcc. It does not use a single compiler which selects target via a switch, like some gcc builds.

Of course, if you build targeting MSYS2 then the resulting executable must be run under MSYS2.

Upvotes: 0

Michael Jaros
Michael Jaros

Reputation: 4681

In your question, you assume that command stands for "Bash syntax".

However, the system() call is calling sh on your Gnu/Linux and cmd.exe on your Windows system. Being interpreted by different shells leads to different results of the two command lines passed into the system() call:

echo 1; echo 2; echo 3;
echo 1 & echo 2 & echo 3;

I don't know if there is any way to make system() call a different command processor on Windows, if COMPSPEC does not seem to affect it.

If you have control over the source code of execinput, I would suggest implementing a more portable execution of command there, e.g. using one of the exec*() system calls together with a defined path to the desired shell.

Upvotes: 1

Related Questions