Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cannot use WSL.exe to invoke Linux commands in PowerShell #5232

Closed
bitcrazed opened this issue May 19, 2020 · 10 comments
Closed

Cannot use WSL.exe to invoke Linux commands in PowerShell #5232

bitcrazed opened this issue May 19, 2020 · 10 comments
Labels

Comments

@bitcrazed
Copy link
Contributor

bitcrazed commented May 19, 2020

@RickStrahl reported this issue in a Twitter conversation with @sundhaug92 and myself, ending here: https://twitter.com/richturn_ms/status/1262885317826113536

Running Win10 x64 with Ubuntu (WSL2) distro with fortune-mod, cowsay, and lolcat installed.

In PowerShell Core x64, invoke simple Linux command, like fortune:

wsl fortune
You will be attacked by a beast who has the body of a wolf, the tail of
a lion, and the face of Donald Duck.

Yay!

Now let's make a cow say it and make it colorful

wsl fortune | cowsay | lolcat
lolcat: The term 'lolcat' is not recognized as the name of a cmdlet, function, script file, or operable program.
Check the spelling of the name, or if a path was included, verify that the path is correct and try again.

SAYWHATNOW?

Lolcat is definitely installed:

wsl echo hello | lolcat
lolcat: The term 'lolcat' is not recognized as the name of a cmdlet, function, script file, or operable program.
Check the spelling of the name, or if a path was included, verify that the path is correct and try again.

No! I KNOW lolcat is intalled ...

wsl lolcat
Hello
Hello
^C

Perhaps PowerShell is parsing the command-line. Let's quote it so it's just a string.

wsl "fortune | cowsay | lolcat"
/bin/bash: fortune | cowsay | lolcat: command not found

SRSLY?

Worked example:
image

So, how DOES one invoke wsl.exe passing an arbitrary command-line script?

@sundhaug92
Copy link

sundhaug92 commented May 19, 2020

Just figured it out!

CMD

wsl echo hello works, so one potential next step is to escape |.
According to this, ^ escapes | : wsl fortune ^| cowsay ^| lolcat

(that's a literal ^, not CTRL+)

Powershell

wsl fortune `| cowsay `| lolcat

@bitcrazed
Copy link
Contributor Author

Thanks for the suggestion @sundhaug92, alas, no cigar

image

@sundhaug92
Copy link

@bitcrazed I've updated the comment, I forgot we were talking pscore rather than cmd.exe

@sundhaug92
Copy link

Because wsl.exe treats each argv as a separate argument (or command), you can't use "". Because you can't use "" you have to find another way to tell the host-shell (cmd, ps, ...) if any to ignore things like |.

When using C#, you can then get away with something like

var pi = new ProcessStartInfo();
pi.FileName = @"C:\Windows\sys" + (IntPtr.Size == 4 ? "native" : "tem32") + @"\wsl.exe"; // Solution for starting 64-bit WSL from a 32-bit process
pi.Arguments = "fortune | cowsay | lolcat";
var p = Process.Start(pi);
p.WaitForExit();

@DHowett
Copy link
Member

DHowett commented May 20, 2020

Piping is a shell feature. You need to pipe in the syntax of the shell you’re invoking, and invoke the shell explicitly to do that.

wsl "sh -c 'fortune | nyancat | dogmoof'"

@therealkenc
Copy link
Collaborator

This is #3284.

With powershell.exe:

image

But on planet sanity, Duntin's answer is better (same as message).

Those '|' characters aren't arguments to a command, they are shell script operators... operators which have arbitrary meaning (if not in practice then in principle). A powershell '|' is unrelated to a Bourne shell '|', notwithstanding the coincidental character choice. Maybe the script you are trying to run uses other shell syntax like '&&' or ';', which might (or might not) be related to a how a powershell interpreter sees the world. Maybe your Linux interpreter of choice is elisp or tcl or perl or python (or pwsh!) instead of a Borne shell like bash. However you roll, call your script against the interpreter. Or if you do the thing a lot, write a colorfulcowfortune.sh and put a shebang at the top.

@RickStrahl
Copy link

RickStrahl commented May 20, 2020

Followed this, but my original question was trying to run multiple commands which works with bash -c but does not work with wsl '<cmd>;<cmd':

image

Notice the error is 'No such file or directory' - it looks like wsl is looking specifically for an executable not a command line perhaps?

Now look at the craziness of stuff that works and what doesn't:

image

The first thing running Code without quotes around anything sort of works and launches Code:

wsl  cd /mnt/c/projects/Test/jekyll/help; code .

But... although it opens, when it does the new path change is lost. code . opens in my host folder (ie. ~) not the folder I changed to in the first command (and it does exist and works with the bash -c command bash after all)

The other commands likely are not working for the same reason - the commands appear to not execute in the same shell context so the bundle command is not found out of that folder context.

Running the same thing with quotes doesn't work at all:

wsl  "cd /mnt/c/projects/Test/jekyll/help; code ."

which is sort of the same thing I'm doing in the previous screen shot.

 wsl  cd /mnt/c/projects/Test/jekyll/help; cd; bundle exec jekyll serve;

This gets me closer - it looks like both commands execute, but the path is not set from the previous command so BOOM again.

Everything explicit seems to be treated as one big command same as the single string:

 wsl  "cd /mnt/c/projects/Test/jekyll/help" "cd" "bundle exec jekyll serve"

@sundhaug92
Copy link

@RickStrahl Try the variant from @DHowett : wsl "sh -c 'cd /mnt/c/projects/Test/jekyll/help; bundle exec jekyll serve;'". Also: That extranous plain cd changes directory to ~.

@therealkenc
Copy link
Collaborator

therealkenc commented May 20, 2020

with bash -c but does not work with wsl '<cmd>;<cmd>'

Running wsl.exe "<cmd>;<cmd>" is the same as (inside Ubuntu) /bin/bash -c "'<cmd>;<cmd>'". Which is something doable albeit unusual.

image

 

wsl cd /mnt/c/projects/Test/jekyll/help; code .

Here /bin/bash was told to change directory and exit. The the semicolon (';') was interpreted by powershell, which then fired up code in your current directory ('.'). Code is in your Windows $env:path and powershell had no trouble finding it.

wsl "cd /mnt/c/projects/Test/jekyll/help; code ."

In this one /bin/bash is trying to run a program called "cd /mnt/c/projects/Test/jekyll/help; code ." which doesn't exist.

wsl cd /mnt/c/projects/Test/jekyll/help; cd; bundle exec jekyll serve;

In this one powershell couldn't find bundle in your $env:path (unlike code previously, where it did).

Your scenario would be something like:

wsl.exe sh -c "cd /mnt/c/projects/Test/jekyll/help; bundle exec jekyll serve"

@bkotch
Copy link

bkotch commented Jul 6, 2020

Thanks @therealkenc. Perfect answer. I completely forgot about invoking sh. Duh.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

6 participants