Use operating system (OS) commands in Haskell programs as if they were native Haskell functions, by treating their inputs and outputs as Haskell streams. This allows you to write high-level Haskell scripts that can perform tasks similar to shell scripts, but with C-like performance, and with strong safety guarantees, refactorability, and modularity.
Use the following imports in the examples below:
>>> :set -XFlexibleContexts
>>> :set -XScopedTypeVariables
>>> :set -XQuasiQuotes
>>> import Data.Function ((&))
>>> import Streamly.Unicode.String (str)
>>> import qualified Streamly.Data.Array as Array
>>> import qualified Streamly.Console.Stdio as Stdio
>>> import qualified Streamly.Data.Fold as Fold
>>> import qualified Streamly.Data.Stream.Prelude as Stream
>>> import qualified Streamly.System.Command as Command
>>> import qualified Streamly.Internal.FileSystem.Dir as Dir
The shell command echo "hello world" | tr [a-z] [A-Z]
can be written as
follows using this package:
>>> :{
Command.toBytes [str|echo "hello world"|] -- Stream IO Word8
& Command.pipeBytes [str|tr [a-z] [A-Z]|] -- Stream IO Word8
& Stream.fold Stdio.write -- IO ()
:}
HELLO WORLD
If you want to execute the same command using the shell pipe syntax:
>>> :{
Command.toBytes [str|sh "-c" "echo 'hello world' | tr [a-z] [A-Z]"|] -- Stream IO Word8
& Stream.fold Stdio.write -- IO ()
:}
HELLO WORLD
You can run commands concurrently by using streamly's concurrent combinators.
Running @grep@ concurrently on many files:
>>> :{
grep file =
Command.toBytes [str|grep -H "pattern" #{file}|] -- Stream IO Word8
& Stream.handle (\(_ :: Command.ProcessFailure) -> Stream.nil) -- Stream IO Word8
& Stream.foldMany (Fold.takeEndBy (== 10) Array.write) -- Stream IO (Array Word8)
:}
>>> :{
pgrep =
Dir.readFiles "." -- Stream IO FilePath
& Stream.parConcatMap id grep -- Stream IO (Array Word8)
& Stream.fold Stdio.writeChunks -- IO ()
:}
Please visit Streamly homepage for more details about streamly.
Available under Apache-2.0 license.