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

add ability to run Windows batch files in bash.exe #1917

Closed
raymod2 opened this issue Apr 14, 2017 · 21 comments
Closed

add ability to run Windows batch files in bash.exe #1917

raymod2 opened this issue Apr 14, 2017 · 21 comments
Labels

Comments

@raymod2
Copy link

raymod2 commented Apr 14, 2017

Currently you can run a batch file using "cmd.exe /c foo.bat" but that is awkward, difficult to type, and possibly inefficient. A better way is to use binfmt like we do for PE files:

sudo sh -c "echo :WindowsBatch:E::bat::/init: > /proc/sys/fs/binfmt_misc/register"

Using this technique you can run the batch file using just "foo.bat". However, the command above needs to be run every time you open a bash window. That is inconvenient especially because it requires root. You can obviate the password check using /etc/sudoers and put the command in your .bashrc but that is not ideal.

Is this something we should consider making part of the default installation? The only downside I can think of is that it won't let you run a bash script that ends in ".bat" but that is an unlikely scenario and in that case the user can rename the file using a more suitable extension such as ".sh".

@aseering
Copy link
Contributor

Ooh, I like that trick.

For .bat files, that should probably be mostly ok? It'd be really nice if it could be generalized. But it quickly becomes ambiguous for other types of scripts.

@CherryDT
Copy link

CherryDT commented Apr 24, 2017

There is .cmd too.

But in general I'm not sure if it should be the default because an extension like cmd is generic enough that it could be used elsewhere and cause unexpected problems. For exe it is OK because even on Linux people may have registered it to launch with Wine.

Just my two cents though.

@mizzao
Copy link

mizzao commented Dec 7, 2017

Right now we can run Windows executables from WSL, but batch files don't do so well:

$ meteor.bat update
/mnt/c/Users/mao/AppData/Local/.meteor/meteor.bat: line 1: @echo: command not found
/mnt/c/Users/mao/AppData/Local/.meteor/meteor.bat: line 2: $'SETLOCAL\r': command not found
/mnt/c/Users/mao/AppData/Local/.meteor/meteor.bat: line 3: SET: command not found
/mnt/c/Users/mao/AppData/Local/.meteor/meteor.bat: line 4: fg: no job control
/mnt/c/Users/mao/AppData/Local/.meteor/meteor.bat: line 5: $'ENDLOCAL\r': command not found
/mnt/c/Users/mao/AppData/Local/.meteor/meteor.bat: line 6: EXIT: command not found
/mnt/c/Users/mao/AppData/Local/.meteor/meteor.bat: line 7: rem: command not found

Would like to see this updated too :)

@eode
Copy link

eode commented Jun 13, 2018

Actually, this should probably be closed, and a new bug opened up to properly handle /etc/binfmt.d.

@eode
Copy link

eode commented Jun 14, 2018

After looking into this further, binfmt is already fully supported (although not via /etc/binfmt.d). Use:

/some/dir$ sudo update-binfmts --install WindowsBat /init --extension bat
/some/dir$ sudo update-binfmts --install WindowsCmd /init --extension cmd    # (if desired)

..sadly, this doesn't work with npm.cmd for me, probably because the environment is too different (the .cmd script runs, but it fails on the JS side).

In any case, it addresses the original issue. When that is set, files with those extensions are treated as scripts for cmd.exe.

Whether that should be a default setting is up to someone else.

@therealkenc
Copy link
Collaborator

therealkenc commented Jun 14, 2018

/some/dir$ sudo update-binfmts --install WindowsBat /init --extension bat
In any case, it addresses the original issue

It repeats the original issue. Your update-binfmts command is the equivalent of:

sudo sh -c "echo :WindowsBatch:E::bat::/init: > /proc/sys/fs/binfmt_misc/register"

@eode
Copy link

eode commented Sep 21, 2018

No, it doesn't just repeat it, it also sets a configuration (somewhere) so it remembers the setting. At least, it did on my system.

@johnnytemp
Copy link

After looking into this further, binfmt is already fully supported (although not via /etc/binfmt.d). Use:

/some/dir$ sudo update-binfmts --install WindowsBat /init --extension bat
/some/dir$ sudo update-binfmts --install WindowsCmd /init --extension cmd    # (if desired)

..sadly, this doesn't work with npm.cmd for me, probably because the environment is too different (the .cmd script runs, but it fails on the JS side).

In any case, it addresses the original issue. When that is set, files with those extensions are treated as scripts for cmd.exe.

Whether that should be a default setting is up to someone else.

update-binfmts works for me. In Ubuntu 18.04.2 LTS, I need to first run sudo apt install binfmt-support to have the update-binfmts command.

@Konfekt
Copy link

Konfekt commented Dec 27, 2019

If you use ZSH, then a suffix alias can be used:

alias -s {cmd,bat}='cmd.exe /c'

@madzaf
Copy link

madzaf commented Jan 8, 2020

If you use ZSH, then a suffix alias can be used:

alias -s {cmd,bat}='cmd.exe /c'

This was not working for script that are not in the current directory due to the difference between windows and unix paths. Because I'm working on a project that sometimes has scripts launching other bat files this was a problem.

I ended up writing the following script :

#!/bin/bash
exec wslpath -w "$1" | cmd.exe /c

Then saved it as /usr/local/bin/wsl_to_cmd (or anywhere in the PATH)

then just defined the alias as follows :

alias -s {cmd,bat}='wsl_to_cmd'

@Konfekt
Copy link

Konfekt commented Jan 8, 2020

Thank you! It is cmd.exe /c above. Also, would eval cmd.exe /c "$(wslpath -w "$1")" achieve the same?

@madzaf
Copy link

madzaf commented Jan 8, 2020

Thank you! It is cmd.exe /c above.

Yes sorry, typo on my end, I updated my answer

Also, would eval cmd.exe /c "$(wslpath -w "$1")" achieve the same?

Even better ! It does look like it works yes !

@raymod2
Copy link
Author

raymod2 commented Jan 8, 2020

What's wrong with the solution I posted 3 years ago?

@Konfekt
Copy link

Konfekt commented Jan 8, 2020

If you mean that in the starting comment, then it lists downsides, such as

the command above needs to be run every time you open a bash window. That is inconvenient especially because it requires root.

@madzaf
Copy link

madzaf commented Jan 8, 2020

If you mean that in the starting comment, then it lists downsides, such as

the command above needs to be run every time you open a bash window. That is inconvenient especially because it requires root.

Running it everytime I launch a wsl window is not ideal. I open a lot of wsl windows. Also the update-binfmts command doesn't seem to work on my machine (although to be fair I didn't look too closely at it).

Being a zsh user I thought if I could do it with an alias, it would be the easiest and least disruptive solution. Also it will carry over with my zshrc if I change computer at some point.

@Konfekt
Copy link

Konfekt commented Jan 8, 2020

Thank you! It is cmd.exe /c above.

Yes sorry, typo on my end, I updated my answer

Also, would eval cmd.exe /c "$(wslpath -w "$1")" achieve the same?

Even better ! It does look like it works yes !

Try

  _wslbatch() { eval cmd.exe /c "$(wslpath -w "$1")"; } &&
  alias -s {cmd,bat}='_wslbatch'

From what I understand about alias -s in man zshall, this should work without any need for an external command in $PATH.

@raymod2
Copy link
Author

raymod2 commented Jan 9, 2020

Running it everytime I launch a wsl window is not ideal. I open a lot of wsl windows. Also the update-binfmts command doesn't seem to work on my machine (although to be fair I didn't look too closely at it).

Being a zsh user I thought if I could do it with an alias, it would be the easiest and least disruptive solution. Also it will carry over with my zshrc if I change computer at some point.

And who is running your 'alias' command for you?? Presumably you put it in your .bashrc and you can do the same with the binfmt command. I've been doing it this way for years. Problem solved and long forgotten...

@madzaf
Copy link

madzaf commented Jan 9, 2020

And who is running your 'alias' command for you?? Presumably you put it in your .bashrc and you can do the same with the binfmt command. I've been doing it this way for years. Problem solved and long forgotten...

You're right I could put it in my .zshrc as well, but, like I said, I couldn't get the binfmt command to work on my end. The alias worked so I went with that. Both solutions are fine really.

@BatmanAoD
Copy link

BatmanAoD commented Mar 29, 2020

One problem I have with cmd.exe /c is that it does not support starting in a WSL path (i.e. a UNC path). So the command needs to be something like:

(start_in="$(wslpath -aw "$PWD")"
cd /mnt/c
cmd.exe /c "pushd $start_in & <some command>)

If the batch file takes arguments, this gets even more complicated. Due to #4868, any filepaths with symlinks anywhere in them need to be resolved prior to passing them to the batch file. Also, when passing filepaths with spaces, they must be escaped for cmd.exe somehow.

This is even uglier, and at the moment I can't actually get it to work. I think giving WSL the ability to run .bat files "natively" would be extremely helpful.

@BatmanAoD
Copy link

My solution above is very similar to one given here, but that one doesn't handle the issues with file-path arguments.

@eode
Copy link

eode commented Feb 1, 2024

This is still unresolved.

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