How could I execute a system command such as cp somefile somedestination in Haskell?
Something like an os.Exec.
The Haskell 98 standard provides:
System.system :: String
-> IO GHC.IO.Exception.ExitCode
which executes a command.
The new System.Process library is more useful though, allowing for portable input/output redirection and so forth.
import System.Process
main = callCommand "cp somefile somedestination"
just works, but you may prefer other functions from the System.Process module.
I'm not a haskell buff, but this may be what you're looking for
If you do this sort of thing a lot then it's worth having a look at http://hackage.haskell.org/package/HSH.
Related
I have a shell script file named /path/to/shell_script.sh which contains a function defintion shell_function() { ...}.
I'd like to be able to do something in Haskell like readProcessWithExitCode shell_function [] "" to eventually get a hold of an IO (String).
How to do this?
If you have a shell script like
#!/bin/bash
foo() {
echo "foo"
}
you can use the readCreateProcess function from the process package to source the script and execute the function in one go, like this:
module Main where
import System.Process
main :: IO ()
main = do
-- I had to put the full path of the script for it to work
result <- readCreateProcess ((shell ". /tmp/foo.sh && foo")) ""
print result
This solution assumes that the script only does things like defining functions and setting environment variables, without running undesired "effectful" code each time it is sourced.
Python or Perl supports:
python xxx.py
perl xxx.pl
powershell xxx.ps1
Execute the script and quit with an exit code. When I tried GHCi (as ghci xxx.hs) it seems to load the xxx.hs file and enter interactive mode, without quiting.
Does the GHC interpreter support such operations?
Does this "interpreting" require to have a main function like the GHC compiler does?
Use runghc to get the same behavior. You will indeed need a main :: IO () function still.
I'm trying to run the elm-reactor project, which is written in Haskell. It fails because it's trying to proc out to the elm command like this:
createProcess (proc "elm" $ args fileName)
My elm executable is sitting in ~/.cabal/bin, which is in my PATH.
The System.Process.proc command searches the $PATH for its command argument, but it doesn't do tilde (~) expansion, so it doesn't find elm.
System.Process.shell has the opposite problem. It does tilde expansion, but it doesn't search the $PATH, apparently.
From the source of the System.Process command, it looks like most everything rests on a foreign ccall to "runInteractiveProcess", which I assume is doing whatever $PATH searching is being done. I don't know where the source for runInteractiveProcess would be, and my C is about 15 years worth of rusty.
I can work around this issue by
a) adding the fully-expanded cabal/bin path to my PATH or
b) symlinking an elm from the working directory to its location in cabal/bin.
However, I'd like to offer a suggested fix to the elm project, to save future adopters the trouble I've gone through. Is there a System.Process call that they should be making here that I haven't tried? Or is there a different method they should be using? I suppose at worst they could getEnv for the PATH and HOME, and implement their own file search using that before calling proc - but that breaks cross-platform compatibility. Any other suggestions?
Try using shell instead of proc, i.e.:
createProcess (shell "elm")
This should invoke elm via a shell, which hopefully will interpret tildes in $PATH as desired.
Update: Here is the experiment I performed to test what shell does...
Compile the following program (I called it run-foofoo):
import System.Process
main = do
(,,_,h) <- createProcess $ shell "foofoo"
ec <- waitForProcess h
print ec
Create a new directory ~/new-bin and place the following perl script there as the file foofoo:
#!/usr/bin/perl
print "Got here and PATH is $ENV{PATH}\n";
Run: chmod a+rx ~/new-bin/foofoo
Test with:
PATH="/bin:/usr/bin:/sbin" ./run-foofoo # should fail
PATH="$HOME/new-bin:/bin:/usr/bin:/sbin" ./run-foofoo # should succeed
PATH="~/new-bin:/bin:/usr/bin:/sbin" ./run-foofoo # ???
On my OSX system, the third test reports:
Got here and PATH is ~/new-bin:/bin:/usr/bin:/sbin
ExitSuccess
My haskell program produces .tex output using my own module.
I can't see my way around having to run 'pdflatex' everytime I want to see a result. I can hardly believe this cannot be done in a more direct manner;
Is there a way to have my code compile the .tex-file?
Is the System.Process package what you are looking for? You can use the function
system :: String -> IO ExitCode
to perform system calls.
$ touch tempfile.txt
$ ghci
GHCi, version 7.6.3: http://www.haskell.org/ghc/ :? for help
>> import System.Process
>> system "ls"
tempfile.txt
ExitSuccess
Not particularly idiomatic, but it gets the job done.
i want to read from a file (contains haskell commands per line). I want to read line by line and execute those and display the result
my following code is not working... print is not processing the command, it is just displaying it:
import System.IO
import Control.Monad
main = do
fileContents <- readFile "Instructions.txt"
mapM_ f (lines fileContents)
f line = do
putStrLn ("Processing Instruction:" ++ line)
print line
instruction file contains haskell commands.
You're probably looking for unsafeEval
http://hackage.haskell.org/packages/archive/plugins/1.5.1.3/doc/html/System-Eval-Haskell.html
But this is almost certainly definitely always a very bad idea for any real program, and not only goes against every guideline and rule of programming but also the fundamental principles of haskell programming.
If you just want something to read a file line by line and output the result, ghc already does this for you pretty well.
ghc -e "command" will execute the command and output to stdout, so it would be pretty easy to write a simple bash script to do this for you:
#!/bin/bash
# linebyline.sh
while read line; do
ghc -e "$line"
done
which you can run by:
cat myfile.txt | linebyline.sh
or you don't even need a separate script:
cat myfile.txt | while read line; do ghc -e "$line"; done
The solution is pretty simple: change print in f to a function which will interpret the line and execute it.
Iit is very easy to use system from System.Cmd and run commands via ghc - e. Your code then becomes
import System.IO
import System.Cmd
import Control.Monad
main = do
fileContents <- readFile "Instructions.txt"
mapM_ f (lines fileContents)
f line = do
putStrLn ("Processing Instruction:" ++ line)
system $ "ghc -e " ++ show line
You still need to add error checking and stuff like that but I'll leave those parts to you since they are not central to the question.