Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/psibi/shell-conduit
Write shell scripts with Conduit
https://github.com/psibi/shell-conduit
conduit scripting shell stream
Last synced: 20 days ago
JSON representation
Write shell scripts with Conduit
- Host: GitHub
- URL: https://github.com/psibi/shell-conduit
- Owner: psibi
- License: bsd-3-clause
- Created: 2014-09-14T20:39:59.000Z (about 10 years ago)
- Default Branch: master
- Last Pushed: 2020-06-20T16:29:37.000Z (over 4 years ago)
- Last Synced: 2024-04-25T23:43:59.171Z (7 months ago)
- Topics: conduit, scripting, shell, stream
- Language: Haskell
- Size: 359 KB
- Stars: 96
- Watchers: 10
- Forks: 16
- Open Issues: 8
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE
Awesome Lists containing this project
README
shell-conduit [![Hackage](https://img.shields.io/hackage/v/shell-conduit.svg?style=flat)](https://hackage.haskell.org/package/shell-conduit) [![Build Status](https://travis-ci.org/psibi/shell-conduit.svg?branch=master)](https://travis-ci.org/psibi/shell-conduit)
=====Write shell scripts with Conduit. Still in the experimental phase.
[Haddock API documentation](https://www.stackage.org/package/shell-conduit).
### Examples
##### Cloning and initializing a repo
``` haskell
import Control.Monad.IO.Class
import Data.Conduit.Shell
import System.Directorymain =
run (do exists <- liftIO (doesDirectoryExist "fpco")
if exists
then rm "fpco/.hsenvs" "-rf"
else git "clone" "[email protected]:fpco/fpco.git"
liftIO (setCurrentDirectory "fpco")
shell "./dev-scripts/update-repo.sh"
shell "./dev-scripts/build-all.sh"
alertDone)
```##### Piping
Piping of processes and normal conduits is possible:
``` haskell
λ> run (ls $| grep ".*" $| shell "cat" $| conduit (CL.map (S8.map toUpper)))
DIST
EXAMPLES
LICENSE
README.MD
SETUP.HS
SHELL-CONDUIT.CABAL
SRC
TAGS
TODO.ORG
```##### Running actions in sequence and piping
Results are outputted to stdout unless piped into other processes:
``` haskell
λ> run (do shell "echo sup"; shell "echo hi")
sup
hi
λ> run (do shell "echo sup" $| sed "s/u/a/"; shell "echo hi")
sap
hi
```##### Streaming
Live streaming between pipes like in normal shell scripting is
possible:``` haskell
λ> run (do tail' "/tmp/example.txt" "-f" $| grep "--line-buffered" "Hello")
Hello, world!
Oh, hello!
```(Remember that `grep` needs `--line-buffered` if it is to output things
line-by-line).##### Handling exit failures
Process errors can be ignored by using the Alternative instance.
``` haskell
import Control.Applicative
import Control.Monad.Fix
import Data.Conduit.Shellmain =
run (do ls
echo "Restarting server ... ?"
killall name "-q" <|> return ()
fix (\loop ->
do echo "Waiting for it to terminate ..."
sleep "1"
(ps "-C" name >> loop) <|> return ())
shell "dist/build/ircbrowse/ircbrowse ircbrowse.conf")
where name = "ircbrowse"
```##### Running custom things
You can run processes directly:
``` haskell
λ> run (proc "ls" [])
dist LICENSE Setup.hs src TODO.org
examples README.md shell-conduit.cabal TAGS
```Or shell commands:
``` haskell
λ> run (shell "ls")
dist LICENSE Setup.hs src TODO.org
examples README.md shell-conduit.cabal TAGS
```Or conduits:
``` haskell
λ> run (cat $| conduit (awaitForever yield))
hello
hello
Interrupted.
```##### Keyboard configuration
``` haskell
import Data.Conduit.Shell
main =
run (do xmodmap ".xmodmap"
xset "r" "rate" "150" "50")
```### How it works
All executable names in the `PATH` at compile-time are brought into
scope as runnable process conduits e.g. `ls` or `grep`.All processes are bound as variadic process calling functions, like this:
``` haskell
rmdir :: ProcessType r => r
ls :: ProcessType r => r
```But ultimately the types end up being:
``` haskell
rmdir "foo" :: Segment r
ls :: Segment r
ls "." :: Segment r
```Etc.
Run all shell scripts with
``` haskell
run :: Segment r -> IO r
```The `Segment` type has a handy `Alternative` instance.
### String types
If using `OverloadedStrings` so that you can use `Text` for arguments,
then also enable `ExtendedDefaultRules`, otherwise you'll get
ambiguous type errors.``` haskell
{-# LANGUAGE ExtendedDefaultRules #-}
```But this isn't necessary if you don't need to use `Text` yet. Strings
literals will be interpreted as `String`. Though you can pass a value
of type `Text` or any instance of `CmdArg` without needing conversions.### Other modules
You might want to import the regular Conduit modules qualified, too:
``` haskell
import qualified Data.Conduit.List as CL
```Which contains handy functions for working on streams in a
list-like way. See the rest of the handy modules for Conduit in
[conduit-extra](http://hackage.haskell.org/package/conduit-extra).Also of interest is
[csv-conduit](http://hackage.haskell.org/package/csv-conduit),
[html-conduit](http://hackage.haskell.org/package/html-conduit), and
[http-conduit](http://hackage.haskell.org/package/http-conduit).Finally, see the Conduit category on Hackage for other useful
libraries:All of these general purpose Conduits can be used in shell
scripting.