Search code examples
windowsbashubuntuwindows-subsystem-for-linux

WSL run linux from windows without spawning a cmd-window


I have WSL bash running in a cmd. I don't use it for anything, it just hangs there to keep the WSL system alive.

When I start X applications:

bash -c "DISPLAY=:0 xmessage hello &"

I get this result:

enter image description here

I can close down the command window without any problems, but it's rather annoying.

How can run commands without getting this cmd window every time?


Solution

  • Here's a simpler solution, which, however, requires a WSH-based helper script, runHidden.vbs (see bottom section):

    wscript .\runHidden.vbs bash -c "DISPLAY=:0 xmessage 'hello, world'"
    

    To apply @davv's own launch-in-background technique to avoid creating a new bash instance every time:

    One-time action (e.g., at boot time): launch a hidden, stay-open bash window. This spawns 2 bash processes: the Windows bash.exe process that owns the console window, and the WSL bash process (owned by the WSL init singleton), which is then available for servicing background commands.

    wscript .\runHidden.vbs bash # hidden helper instance for servicing background commands
    

    For every X Window-launching command: Terminate each command with & to have it be run by the hidden WSL bash instance asynchronously, without keeping the invoking bash instance alive:

    wscript .\runHidden.vbs bash -c "DISPLAY=:0 xmessage 'hello, world' &"
    

    runHidden.vbs source code:

    ' Simple command-line help.
    select case WScript.Arguments(0)
    case "-?", "/?", "-h", "--help"
      WScript.echo "Usage: runHidden executable [...]" & vbNewLine & vbNewLine & "Runs the specified command hidden (without a visible window)."
      WScript.Quit(0)
    end select
    
    ' Separate the arguments into the executable name
    ' and a single string containing all arguments.
    exe = WScript.Arguments(0)
    sep = ""
    for i = 1 to WScript.Arguments.Count -1
      ' Enclose arguments in "..." to preserve their original partitioning, if necessary.
      if Instr(WScript.Arguments(i), " ") > 0 then
        args = args & sep & """" & WScript.Arguments(i) & """"
      else
        args = args & sep & WScript.Arguments(i)
      end if
      sep = " "
    next
    
    ' Execute the command with its window *hidden* (0)
    WScript.CreateObject("Shell.Application").ShellExecute exe, args, "", "open", 0
    

    Even when launched from a GUI app (such as via the Run dialog invoked with Win+R), this will not show a console window.

    If your system is configured to execute .vbs scripts with wscript.exe by default (wscript //h:wscript /s, which, I think, is the default configuration), you can invoke runHidden.vbs directly, and if you put it in your %PATH%, by filename (root) only: runHidden ....

    Note that use of the script is not limited to console applications: even GUI applications can be run hidden with it.