1

My current WSL2 + ConEmu + bash/zsh setup works as expected.

I have some aliases set up in my .zshrc:

//.zshrc
alias mycommand1="[does some stuff]"
alias mycommand2="[does other stuff]"

What I want to achieve is to have a ConEmu startup Task that would run mycommand1 and mycommand2 in two separate tabs, and then leave these tabs open.

This requires ConEmu to load up WSL+bash+zsh, and then run the command.

As per the docs, my default Task currently runs native wsl.exe:

// {Bash::bash} Task commands
%windir%\system32\wsl.exe -cur_console:pm:/mnt --distribution Ubuntu-20.04

And, after carefully reading all the docs (1, 2, 3) and spending a fair amount of time on fiddling with params, I was only able to produce following attempts:

%windir%\system32\wsl.exe --distribution Ubuntu-20.04 -new_console:pm:/mnt -- ls
// logs my Windows User directory and prompts "Press Enter or Esc to exit..."
%windir%\system32\wsl.exe --distribution Ubuntu-20.04 -new_console:pm:/mnt -- mycommand1
// logs "zsh:1: command not found: mycommand1" and prompts "Press Enter or Esc to exit..."

I would appreciate some pointers:

  • How can I pass a command from wsl.exe that will be run from within the Ubuntu context, with all my bash/zsh configs?
  • How can I do that from ConEmu Task, ensuring that after running the command the tabs stay open with a regular zsh shell prompt?
  • Is there anything else I need to know to solve my problem?
JoannaFalkowska
  • 2,771
  • 20
  • 37
  • Have you tried [this](https://stackoverflow.com/a/66954673/13020139) for passing commands to Ubuntu from `wsl.exe`? The only thing I'm not sure about is if you need to run `source ~/.bashrc` first (and whatever other configs you need to load up). – wxz Apr 06 '21 at 17:05
  • I'm guessing the downvote is because someone thought this wasn't necessarily a "programming question", but I disagree (although barely). At its core, it goes to shell scripting, a topic that is allowed on Stack Overflow. Admittedly, the fact that it is wrapped up in a ConEmu question does obscure that a bit, though. – NotTheDr01ds Apr 06 '21 at 19:30
  • Although if the downvote is because it contains "multiple questions", then fair enough ;-) – NotTheDr01ds Apr 06 '21 at 19:50
  • @NotTheDr01ds I agree it is a "question wrapped in another question" case, but I really wanted to avoid falling into an X/Y problem trap. I don't feel competent enough in this field (yet) to split this case into separate concise questions. – JoannaFalkowska Apr 07 '21 at 12:08
  • No worries, I agree, and I upvoted since you've clearly done your research. – NotTheDr01ds Apr 07 '21 at 18:16

2 Answers2

2

Adding this as a second answer in case it works for you (and it very well may).

My (very long) other answer assumes that you need the alias to run in the same subshell instance that continues to run. If you are okay with the alias running, then exec'ing a new shell, then this answer will be much simpler.

Just create a conemu_start.txt (or whatever you want to call it, wherever you want to place it), with the following:

>%windir%\system32\wsl.exe -cur_console:t:"MyCommand1" -cur_console:pm:/mnt ~ --distribution Ubuntu-20.04 --exec zsh -li -c "mycommand1; zsh -li"
>%windir%\system32\wsl.exe -cur_console:t:"MyCommand2" -cur_console:pm:/mnt ~ --distribution Ubuntu-20.04 --exec zsh -li -c "mycommand2; zsh -li"

As with the other answer, in ComEmu, set Settings -> Startup -> Tasks file to this file.

That's it. The -li will cause the shells to be login (which processes .zprofile) and interactive (which processes .zshrc). That way, the aliases get defined, executed, and then another subshell is run to keep the ConEmu tab open.

NotTheDr01ds
  • 15,620
  • 5
  • 44
  • 70
1

Short answer:

  • Create a new startup directory with a new .zshrc that (a) sources the existing profile, and (b) runs aliases based on an environment variable set before starting the shell.
  • Start each shell (tab) by setting ZDOTDIR, RUN_ALIAS, and execing zsh -li
  • Run these through the wsl.exe command
  • Set a ConEmu startup file to run the appropriate commands

Step 1: Launch zsh, run an alias, and keep the session from exiting

Assumptions: I'm going to assume you really do want these to be aliases. If you want to run other arbitrary scripts/commands, you can still do it, but it will require a slight change to the instructions. I've summarized the changes needed in-line below.

There are several techniques you could use to keep the shell running, but the ones suggested in this question require you to either:

  • Create a nested shell, which is not ideal.
  • Or modify your existing ~/.zshrc to "special case" a launch with your command. It's a neat trick, but I'm not a fan of changes to the default startup files when they can be avoided. That said, it's much easier. If you want to go this route, I'll add some info at the bottom of this answer on how to do it.

But the ~/.zshrc solution got me thinking. If you want to run any arbitrary command at startup, and yet keep the shell running, the answer is .zshrc. You just need to have a different .zshrc that you use for the "special case".

bash has the --rcfile option to select the file to run at startup, but the zsh equivalent is a bit trickier, as it involves setting $ZDOTDIR and changing the location from which zsh reads its startup (from this answer).

So to start, let's create a config directory for your "run an alias" config:

mkdir -p ~/.local/share/zsh/startup/run_alias/`

Or wherever you want, of course. Then, in that directory, create the following:

~/.local/share/zsh/startup/run_alias/.zshrc:

if [ -f $HOME/.zshrc ]; then
  . $HOME/.zshrc
fi

if [ -v RUN_ALIAS ] && alias | grep -q "^$RUN_ALIAS="; then
  eval "$RUN_ALIAS"
fi

unset RUN_ALIAS
unset ZDOTDIR

And ~/.local/share/zsh/startup/run_alias/.zprofile:

if [ -f $HOME/.zprofile ]; then
  . $HOME/.zprofile
fi

The conditionals, of course, are optional if you always know that your $HOME/.zsh and .zprofile exist. But better to be safe.

Repeat for mycommand2.

If it's not obvious, this will:

  • Call your existing $HOME/.zshrc to define the aliases (and anything else in your startup)
  • Check to make sure the contents of $RUN_ALIAS really is an alias (some added security)
  • Call the alias defined in the RUN_ALIAS variable
  • Unset the RUN_ALIAS variable (cleanup)
  • Unset the special ZDOTDIR so that future subshell invocations will use the files in $HOME.
  • Have the new .zprofile source the original as well

You can now test this by calling a subshell with:

ZDOTDIR=~/.local/share/zsh/startup/run_alias RUN_ALIAS=mycommand1 zsh -li

But of course, that leaves an extra subshell running ($SHLVL is 2). So, use exec instead:

ZDOTDIR=~/.local/share/zsh/startup/run_alias RUN_ALIAS=mycommand1 exec zsh -li

$SHLVL is now 1, your command/alias should have been executed in the current (and only) shell, and it is still running.

To get that running in WSL, we do need to start an "outer shell" (that is replaced by execing the proper zsh). I tend to use sh for this, like so:

wsl ~ --distribution Ubuntu-20.04 --exec sh -c "ZDOTDIR=`$HOME/.local/share/zsh/startup/run_alias RUN_ALIAS=mycommand1 exec zsh -li" # PowerShell quoted
wsl ~ --distribution Ubuntu-20.04 --exec sh -c "ZDOTDIR=$HOME/.local/share/zsh/startup/run_alias RUN_ALIAS=mycommand1 exec zsh -li" # CMD (and ConEmu) quoted

Side note: My Windows Terminal profiles for wsl actually used to look very similar to this. I've streamlined them a bit, but I still set an environment variable (the title I want for the tab) before starting my shell (fish) and tmux.

Side note #2: My original answer used two separate ZDOTDIR's and corresponding directories. This would still be useful if you wanted to execute different commands (as opposed to aliases). In that case, create additional directories, and point to them by changing the ZDOTDIR. Just put your commands in the modified .zshrc in the corresponding directory.

Run the commands at ConEmu Startup

The easy part. Create a conemu_start.txt anywhere (and any name), really:

>%windir%\system32\wsl.exe -cur_console:t:"MyCommand1" -cur_console:pm:/mnt ~ --distribution Ubuntu-20.04 --exec sh -c "ZDOTDIR=$HOME/.local/share/zsh/startup/run_alias RUN_ALIAS=mycommand1 exec zsh -li"
>%windir%\system32\wsl.exe -cur_console:t:"MyCommand2" -cur_console:pm:/mnt ~ --distribution Ubuntu-20.04 --exec sh -c "ZDOTDIR=$HOME/.local/share/zsh/startup/run_alias RUN_ALIAS=mycommand2 exec zsh -li"

In ComEmu, set Settings -> Startup -> Tasks file to this file.

That should do it. Starting ConEmu should now open two tabs with zsh, one for each of these aliases/commands.

Alternative: Modify existing .zshrc to run an alias based on an environment variable

Add the following to the bottom of ~/.zshrc:

if [ -v RUN_ALIAS ] && alias | grep -q "^$RUN_ALIAS="; then
  eval "$RUN_ALIAS"
fi

Test it with:

RUN_ALIAS=mycommand1 exec zsh -li

And then change the conemu_start.txt to:

>%windir%\system32\wsl.exe -cur_console:t:"MyCommand1" -cur_console:pm:/mnt ~ --distribution Ubuntu-20.04 --exec sh -c "RUN_ALIAS=mycommand1 exec zsh -li"
>%windir%\system32\wsl.exe -cur_console:t:"MyCommand2" -cur_console:pm:/mnt ~ --distribution Ubuntu-20.04 --exec sh -c "RUN_ALIAS=mycommand2 exec zsh -li"
NotTheDr01ds
  • 15,620
  • 5
  • 44
  • 70