'How can I direct PowerShell 7 to run a bash (Ubuntu) script in WSL2 on Windows 10?
I want to put together a PowerShell script that invokes bash/wsl and runs the following code on the working directory in bash:
for f in $(find -type l);do cp --remove-destination $(readlink $f) $f;done;
All I can seem to do is get wsl to change directories:
param (
[Parameter(Mandatory=$true,Position=0)]
[String]$Folder
)
wsl.exe --cd $Folder
I've tried:
wsl -c 'for f in $(find -type l);do cp --remove-destination $(readlink $f) $f;done;'
wsl.exe 'for f in $(find -type l);do cp --remove-destination $(readlink $f) $f;done;'
Also, for some reason, I can't get any additional commands to work after I've called wsl.exe the first time. For instance, the following doesn't work:
param (
[Parameter(Mandatory=$true,Position=0)]
[String]$Folder
)
wsl.exe --cd $Folder
wsl.exe echo "Hello World" # Never executes
I'm pretty inexperienced with linux and Ubuntu for that matter, so I have a feeling I'm missing something incredibly simple - thus this post.
How can I execute a bash/wsl2 command from Windows Powershell 7?
Any help greatly appreciated.
Solution 1:[1]
I have a feeling I'm missing something incredibly simple
Not really. In my experience, calling one scripting language from another is rarely what-I-would-call "simple" ;-).
That's a good attempt to figure it out from the help, but unfortunately there's just not enough detail in the wsl --help output to figure it out from that.
As noted in the help, though, there are a few constructs available for running commands in a WSL instance using the wsl.exe command.
wsl <commandline>: Runs the command line as an argument to the default shell.wsl -e <command>: Runs the command in place of the shell
Note that, for the sake of safety, I'm going to replace your command-lines with more benign versions ;-).
for f in $(find -xdev -type l); do echo $f "----" $(readlink $f); done
Side note: As someone once pointed out to me when I used find with for -- Why is looping over find's output bad practice?, so it would really be better off as find -xdev -type l | xargs -I % sh -c "echo -n % '---- '; readlink %", but we're going to leave it in a for loop to demonstrate part of the problem here.
The following two tries fail because ...
wsl --cd ~ -c 'for f in $(find -xdev -type l); do readlink $f; done'-cis not a flag that is understood bywsl.exewsl.exe --cd ~ 'for f in $(find -xdev -type l); do readlink $f; done'That would be the equivalent of runningcd ~; for f in $(find -xdev -type l); do readlink $f; done, which won't work either, of course.Actually, in retrospect, this might work for you. It failed for me because my default shell is Fish, but
wsldoes seem to attempt to run the default shell with-cfor whatever command-line is passed in.It may have failed for you because you weren't setting the directory (via
--cd) on the same command-line before calling it.wsl.exe --cd ~ -e 'for f in $(find -xdev -type l); do readlink $f; done'And, while you didn't mention trying this, this particular one won't work either, since
-eneeds to be a single "command", but that's a full commandline with shell builtins such asfor.
"Aaargggh!", you've been saying, right? Catch 22? You need -c to get to the shell, but the wsl command can't pass it.
So, we use:
wsl --cd ~ -e sh -c 'for f in $(find -xdev -type l); do echo $f "----" $(readlink $f); done'
That:
- Changes to the home directory (you can replace with the
$FOLDERvariable from PowerShell, of course) - Executes the
shshell (you could also use Bash (or any other shell or command) if you need any of its constructs) - Passes the commandline via
-cto the shell. This is a fairly normal argument for most shells, POSIX or otherwise.
Note (from experience) that quoting rules between PowerShell and WSL/sh can get fairly "unruly". I find that as the example gets more complicated, it's often better to put the shell commands in a script inside WSL, which you then execute from PowerShell. For example, something like:
wsl --cd ~ -e sh -c "~/.local/bin/myscript.sh"
--cd note
Using two separate wsl commands, like in your --cd example:
wsl.exe --cd $Folder
wsl.exe echo "Hello World" # Never executes
Assuming you were executing that via a script, the first line:
- Changes to the specified directory
- Runs the default shell, so you are then in an interactive session
If you then exit the shell (Ctrl+D or exit), then you should see the output from the second command.
You can also see this interactively if you run it from PowerShell via:
wsl --cd ~ ; wsl echo Hello
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 |
