5

I am using make from inside MSYS2 project, in general without problems. However, if I use zsh, I am unable to switch subsystems. For example:

source shell mingw64

gives:

/usr/bin/shell:58: bad substitution

Clearly, there is bash specific code in the shell script and the script is sourced because it sets environment variable in the calling shell.

One could fix this amending shell code, but that could be overwritten or become incompatible, after the next pacman -Syu.

Is there a general solution to source Bash scripts in zsh (or a solution specific for switching MSYS subsystem)?

Charles Duffy
  • 280,126
  • 43
  • 390
  • 441
antonio
  • 10,629
  • 13
  • 68
  • 136
  • 2
    You should probably make a pull request to https://github.com/AlexPux/MSYS2-packages if you care about this. – David Grayson Feb 12 '18 at 23:45
  • Right now, it's not clear what role `make` plays in any of this. Is the `source` command being called *from a `Makefile`*? Can you provide a [mcve]? If your one `source shell mingw64` command *is* a MCVE, what does Make have to do with the issue at all? – Charles Duffy Feb 22 '18 at 19:05
  • @CharlesDuffy: Yes, the MCVE is `source shell mingw64` executed in zsh. I mention `make` because the compelling reason to use MSYS2 is to "make" binaries of GNU/POSIX programs in Windows. You obtain POSIX emulation under the mingw subsystem and native binaries switching to the mingwXX subsystem. Of course, nothing prevents to use MSYS2 just for the fun of using Linux shells, e.g zsh. In the latter case `shell` does not work. I am not asking how to source zsh from bash because I don't think there's a general solution. However, it _should_ be possible to switch MSYS2 subsystem from zsh too. – antonio Feb 22 '18 at 22:56
  • @antonio, ...which is why there's an open ticket upstream asking for a version of the msys `shell` command compatible with all POSIX-compliant shells. Anyhow, as far as I can tell without getting a Windows system together (or auditing the `shell` command's source to determine if it does anything that can't be inherited through the environment), I've answered your question; if you use the `bash -c` command given, it should launch a new zsh shell configured to build software for the mingw64 target. – Charles Duffy Feb 22 '18 at 23:03

1 Answers1

1

You can't interpret arbitrary bash scripts in zsh, but you can start a new copy of bash with directions to source a script and then hand over control to a zsh interpreter:

bash -c 'set -a; source shell mingw64 && exec zsh -i'

That zsh interpreter will thus inherit exported environment variables and working directory changes made by sourcing the bash script; it will not inherit shell-local (non-exported) variables, aliases or functions.

set -a instructs bash to export all variables by default, thus ensuring that variables set by your sourced script are whenever possible placed in the environment rather than kept shell-local. This won't work for values of types that can't be exported (such as arrays), but is a reasonable interim measure.


By the way -- there's an upstream ticket calling for this code to be made compatible with /bin/sh. Should that happen, zsh will be able to interpret it when in POSIX-compatibility mode, which you can temporarily enter as follows:

emulate sh -c 'source shell mingw64'
Charles Duffy
  • 280,126
  • 43
  • 390
  • 441
  • For some reason: `x=123`, `bash -c 'set -a; source shell mingw64 && exec zsh -i` and `echo $x` does not give `123`. Also, after some of subsystem switches, there will be a lot of zsh processes. So one should add a `kill -9 parent-shell-pid` (perhaps through a zsh function/alias wrapping `shell`) – antonio Feb 22 '18 at 23:42
  • @antonio, you need to `export x` before calling `bash`, or use `set -a` to enable automatic export before defining the variable. And no, you **definitely** don't want to kill your parent process -- if you don't want to leave one behind, use `exec` to replace the current shell with the child and not leave a parent process behind at all; `exec bash -c 'set -a; source shell mingw64 && exec zsh -i'` doesn't increase the number of running processes in memory at all, since the old zsh instance replaces itself with bash, which then replaces itself with zsh again. – Charles Duffy Feb 22 '18 at 23:46
  • @antonio, ...even when killing a process is a good idea, btw, `kill -9` almost universally isn't -- it prevents your process from being able to clean up after itself, and should be used only if there's a failure that prevents it (ie. if the cleanup process itself is hanging). Use SIGTERM, not SIGKILL, unless you have an *extremely* compelling reason to do otherwise. – Charles Duffy Feb 22 '18 at 23:50