6
$\begingroup$

This question already has an answer here:

Now windows 10 comes with exciting new feature called "Bash on Ubuntu on Windows " and its core is windows sub linux system(also called wsl).

That means we can use linux tools seamlessly on windows either using bash or if we insist using cmd, we can done it by

bash -c 'linux command'

like this

enter image description here

As far as I know, running external command inside Mathematica is assumed to be inside windows cmd. However, I found bash -c is not working in Mathematica.

Try this

ReadList["!echo good"]  (*windows echo*)
good
ReadList["!bash -c 'echo good'"]  (*linux echo)
{\.19曪謺, Null, Null, Null}

What is wrong? How to use bash inside mathematica? This is so important, because we can get the power of sed, awk, ... and a bunch of others. Though windows can install unix tools set like GOW, However, I found command like sed in GOW is not as quick as wsl.

update I found

ReadList@"!C:\\Windows\\System32\\bash.exe -c 'echo good'"`

will give errors

ReadList::readt: Invalid input found when reading .19:f27a from !C:\Windows\System32\bash.exe --login -c 'echo good'.

as george2079 suggested, I tried

RunProcess[{"bash", "-c", "'echo good'"}]

However, I got

enter image description here


update2017-4-18

upgrade to win 10 creator, bash is working properly.

RunProcess[{"bash", "-c", "a=111;echo \$a"}] (*notice there are no single quotes, and $ have to be escaped*)

gives

<|"ExitCode" -> 0, "StandardOutput" -> "111", "StandardError" -> ""|>
$\endgroup$

marked as duplicate by Emilio Pisanty, Jason B., WReach, gwr, J. M. is away Mar 25 '17 at 7:50

This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.

  • 1
    $\begingroup$ I wrote a small package a while back that uses Cygwin and RunProcess to achieve this. Let me know if you're interested and I can share it. It's quite simple but I would welcome some additional eyes on it with the idea of improving. $\endgroup$ – rfrasier Mar 22 '17 at 8:20
  • $\begingroup$ Hi, @rfrasier-mlp. Thank you for comment. Would you like to post an answer? $\endgroup$ – matheorem Mar 22 '17 at 8:35
  • $\begingroup$ Try using RunProcess $\endgroup$ – george2079 Mar 22 '17 at 16:17
  • 1
    $\begingroup$ @EmilioPisanty and you said if cmd can run bash -c, then Run will work. But the problem is that `bash -c' works perfectly in cmd, while Mathematica just doesn't work with bash -c $\endgroup$ – matheorem Mar 22 '17 at 16:28
  • 2
    $\begingroup$ The issue is known and is re: bash not playing nice to pipes to stdout, see for example : github.com/Microsoft/BashOnWindows/issues/2 $\endgroup$ – george2079 Mar 22 '17 at 16:38
4
$\begingroup$

I have written a small but useful package for running Cygwin from Mathematica. It's certainly not complete but I hope it is helpful for someone. Please let me know if you plan to make any changes.

To use the package you need to install Cygwin as well as a folder in the package directory called /BatchScripts which holds a batch script for running Cygwin in "command mode".

I use (babun) on my dev machine, a nice Cygwin shell with a lot of features. Notably, it installs in your user home directory and thus does not require admin rights, which is useful at my firm for things like ssh and text file processing without a fuss from admins. On the server that I use, I have Cygwin64 installed. The batch script file can set the appropriate environment variables for any installation---I just have settings for babun and for Cygwin64 but you can set your own for your Cygwin install. Here's the code for the batch script you can save as CygwinCommandMode.bat:

@ECHO OFF

REM Check if babun cygwin is installed
IF EXIST "%USERPROFILE%\.babun\cygwin" (
    SET CYGWIN_PATH=%USERPROFILE%\.babun\cygwin
)

REM Check if cygwin64 is installed
IF EXIST "%SystemDrive%\cygwin64" (
   SET CYGWIN_PATH=%SystemDrive%\cygwin64
)

REM Check if CYGWIN_PATH environment variable has been set
IF "%CYGWIN_PATH%"=="" (
    ECHO ERROR: The CYGWIN_PATH environment variable is not defined.
    ECHO The installation path of Cygwin cannot be found.
    EXIT /B 1
)

REM Check if the typical cygwin home directory exists
IF EXIST "%CYGWIN_PATH%\home\%USERNAME%" (
    REM Set the CYGWIN_HOME environment variable to the user's typical cygwin home directory (e.g. /home/<username>/)
    SET CYGWIN_HOME=%CYGWIN_PATH%\home\%USERNAME%
) ELSE (
    ECHO ERROR: The typical value for the Cygwin home directory cannot be found.
    EXIT /B 1
)

REM If the /bin directory is not in the cygwin home directory, then create it
IF NOT EXIST "%CYGWIN_HOME%\bin" (
    MKDIR "%CYGWIN_HOME%\bin"
)

REM Add the paths to the PATH environment variable
SET PATH=%CYGWIN_PATH%\bin;%CYGWIN_HOME%;%CYGWIN_HOME%\bin;%PATH%

REM Run bash in command mode passing the script command line argument with quotes around it
%CYGWIN_PATH%\bin\bash.exe --login -c "%~1"

The code for the package is as follows with the package .m file as follows:

(* Mathematica Package *)
(* Created by Mathematica Plugin for IntelliJ IDEA *)

(* :Title: CygwinLink *)
(* :Context: CygwinLink` *)
(* :Author: rfrasier *)
(* :Date: 2017-03-09 *)

(* :Package Version: 1.1.0 *)
(* :Mathematica Version: +10.0.0 *)
(* :Copyright: (c) 2017 rfrasier *)
(* :Keywords: windows, cygwin, bash, shell, unix, linux, command *)
(* :Discussion: *)

BeginPackage["CygwinLink`"]
(* Exported symbols added here with SymbolName::usage *)

(* unprotect and clear all variables prior for easier reloading of package *)
Unprotect["CygwinLink`*"];
ClearAll["CygwinLink`*"];

(* cygwin installation *)
$CygwinBatchFileName = "Cygwin.bat";
$DefaultCygwinInstallationPath = "C:\\cygwin64";
$CygwinInstallationPath = $DefaultCygwinInstallationPath;
$CygwinBatchFilePath = FileNameJoin[{$CygwinInstallationPath, $CygwinBatchFileName}];
$CygwinInstalledQ = FileExistsQ[$CygwinBatchFilePath]; (* this runs once *)

(* cygwin command mode batch file path *)
$CygwinCommandModeBatchFilePath = FileNameJoin[{DirectoryName[$InputFileName], "BatchScripts", "CygwinCommandMode.bat"}];
(* TODO check if cygwin batch scripts folder and scripts exist *)

(* Exported symbols added here with SymbolName::usage *)
Bash::usage = "Bash[command] runs the specified Unix bash shell command using Cygwin and returns a list of the output lines.";

Begin["`Private`"]

(* run bash command function *)
runBashCommand[command_String] :=
    Module[{assoc, output},
      assoc = RunProcess[$SystemShell, All, $CygwinCommandModeBatchFilePath <> " \"" <> command <> "\"\n", ProcessDirectory -> FileNameJoin[{Replace["SystemDrive", GetEnvironment["SystemDrive"]]}]];
      output = Block[{result}, StringCases[assoc["StandardOutput"], command ~~ "\"" ~~ result___ ~~ "\n" -> result]]
    ];

(* bash function *)
Bash[command_String] /; StringLength[command] > 0 :=
    Module[{commandOutput, printOutput},
      commandOutput = runBashCommand[command];
      printOutput = StringSplit[StringTrim[First@commandOutput], "\n"];
      printOutput
    ];

End[] (* `Private` *)

EndPackage[]
$\endgroup$
  • $\begingroup$ Hi, rfrasier-mlp. Thank you very much for sharing. babun is really impressive. However, since I installed it on no default folder, I currently can't get your function work. I'll try it later. But do you work on win 10 now? Have you tried msdn.microsoft.com/en-us/commandline/wsl/about ? It is awesome, it can work directly with files on windows drive. $\endgroup$ – matheorem Mar 22 '17 at 16:12
  • $\begingroup$ I found ReadList@"!D:\\babun-1.2.0\\.babun\\cygwin\\bin\\bash.exe -c 'echo good'" gives right result. However, ReadList@"!C:\\Windows\\System32\\bash.exe -c 'echo good'" will gives error. Don't know what is the difference between cygwin's bash and wsl's bash $\endgroup$ – matheorem Mar 22 '17 at 16:15
  • $\begingroup$ and also as I test it, sed in cygwin is less efficient than wsl $\endgroup$ – matheorem Mar 22 '17 at 16:38
  • $\begingroup$ @matheorem, this sounds like a post for the StackExchange bash scripting thread or whichever is most relevant. Perhaps you could elaborate briefly on your findings for sed having performance differences across platforms and it would be nice to link to any URLs where this is addressed on SE. Thanks for your work! $\endgroup$ – rfrasier Apr 20 '17 at 1:06

Not the answer you're looking for? Browse other questions tagged or ask your own question.