In GHCi, a shell command can be executed using :!<command>. By default, it seems that the sh shell is used:
Prelude> :!echo $0
/bin/sh
I have a number of aliases and custom functions defined for the shell I use generally on my system (fish), and I'd like to use these from GHCi but not have to translate them into sh-compatible versions.
Is there a way of changing the shell GHCi uses to execute :! commands? I haven't been able to find any :set options for this, nor any command-line arguments to GHCi to do this.
The :! command in current versions of ghci is a call to System.Process.system
-- | Entry point for execution a ':<command>' input from user
specialCommand :: String -> InputT GHCi Bool
specialCommand ('!':str) = lift $ shellEscape (dropWhile isSpace str)
-- [...]
shellEscape :: String -> GHCi Bool
shellEscape str = liftIO (system str >> return False)
I suspect system is hardcoded to /bin/sh, but there's no reason you can't define your own ghci command to do fish calls. I don't have fish installed, so I'll use bash as an example:
λ import System.Process (rawSystem)
λ :def bash \cmd -> rawSystem "/bin/bash" ["-c", cmd] >> return ""
λ :bash echo $0
/bin/bash
Related
How can I replicate ghci -e "print 123" in cabal v2-repl?
I've searched for "expression" or "statement" in cabal v2-repl --help with no luck.
The simplest way is to use shell piping capabilities. See:
% cabal v2-repl <<< ':type zip'
...
λ zip :: [a] -> [b] -> [(a, b)]
λ Leaving GHCi.
This <<< notation, in sh script interpreter, means that the quoted string is sent to the standard input of the command, followed by newline, then end of file.
There are other ways. For example, if you wish to supply more lines, you can use the so-called "here-doc":
% cabal repl <<EOF
:type zip
:type fst
EOF
The <<< notation is a shorthand for a one-line "here-doc".
In general, a program may know whether its standard input is a terminal (assuming, live user) or a file (which heredoc pretends to be), and behave differently. But ordinarily it would work either way, and, if you can send things to its standard input, you can automate it.
Is there any way I can run GHCi on command line like a regular command in shell?
For example: :browse in GHCi - list all the function for specific module.
but I want to run it on shell, e.g.: ghci --browse "MyModule"
which lists all the functions for the module
I know hoogle can run it on shell, e.g: hoogle Monad
The easiest way is to pipe in the commands via standard input. In Bash this can be done nicely with a “here-string”:
$ ghci <<< ':t reverse'
GHCi, version 8.2.1: http://www.haskell.org/ghc/ :? for help
Loaded GHCi configuration from /home/sagemuej/.ghci
Loaded GHCi configuration from /home/sagemuej/.ghc/ghci.conf
Prelude> reverse :: [a] -> [a]
Prelude> Leaving GHCi.
Use verbosity 0 to avoid all the greeting stuff:
$ ghci -v0 <<< ':t reverse'
reverse :: [a] -> [a]
Intuitively, I've tried
$ ghc -e "import System.Environment" -e "getArgs" -- a b c
ghc: unrecognised flag: --
did you mean one of:
-n
-F
-v
Usage: For basic information, try the `--help' option.
$
...without success.
I was expecting the output to be along the lines of ["a","b","c"].
The docs here don't seem to mention any way to pass cli arguments through.
AFAIK piping in stdio works as expected.
And perhaps if it is not possible to pass in arguments with ghc -e, maybe it's still possible with ghci to supply both some code, some arguments to it, run, then exit?
To answer the second part of the question:
Prelude> :help :main
Commands available from the prompt:
…
:main [<arguments> ...] run the main function with the given arguments
…
Prelude> let main = System.Environment.getArgs >>= print
Prelude> :main foo bar
["foo","bar"]
Consider the following Haskell function:
eraseFile :: FilePath -> IO ()
eraseFile basename =
do let cmd' = ">"
args' = ("/path/to/file/" ++ basename) :: String
(exitcode', stdout', stderr') <- readProcessWithExitCode cmd' [args'] ""
return ()
When I try to run this in a stack ghci repl, or from the main function, I get a permission denied error from the console. Normally, in a bash console, you could just run this command as sudo, but this doesn't seem to work when invoked from Haskell.
Question: How to execute system commands in Haskell as root?
As already pointed out in the comments, you can just run the entire stack/ghc under root, but I daresay that's a bad idea. Preferrably, I'd just invoke sudo as a process from within your program. The particular command – emptying a file, if I have understood that correctly? – is then easiest done with tee:
do let cmd' = "sudo"
args' = ["tee", "/path/to/file/" ++ basename :: String]
(exitcode', stdout', stderr') <- readProcessWithExitCode cmd' args' ""
As Zeta remarks, truncate --size 0 would probably be a cleaner command.
To get around password entering, you probably also want to make an exception in the sudoers file. It's a hairy matter; of course the really best thing would be if you could avoid needing root permissions altogether.
Is there a way to chain :reload/:r along with :main as a single command in GHCi?
The goal here is to avoid typing both every time I change something in my other terminal, but to just type ↑Enter.
:cmd seems to accept string with multiple lines.
Therefore you can do the following command.
:cmd return $ unlines [":reload",":main"]
also you can add following code to ~/.ghci
:def hoge const $ return $ unlines [":reload",":main"]
now you can execute :hoge in ghci