{"id":13647048,"url":"https://github.com/psibi/shell-conduit","last_synced_at":"2025-04-09T20:09:36.329Z","repository":{"id":20748412,"uuid":"24032869","full_name":"psibi/shell-conduit","owner":"psibi","description":"Write shell scripts with Conduit","archived":false,"fork":false,"pushed_at":"2020-06-20T16:29:37.000Z","size":368,"stargazers_count":96,"open_issues_count":8,"forks_count":15,"subscribers_count":9,"default_branch":"master","last_synced_at":"2025-04-09T20:09:29.076Z","etag":null,"topics":["conduit","scripting","shell","stream"],"latest_commit_sha":null,"homepage":null,"language":"Haskell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/psibi.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2014-09-14T20:39:59.000Z","updated_at":"2023-01-24T17:47:02.000Z","dependencies_parsed_at":"2022-08-20T23:10:09.556Z","dependency_job_id":null,"html_url":"https://github.com/psibi/shell-conduit","commit_stats":null,"previous_names":[],"tags_count":13,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/psibi%2Fshell-conduit","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/psibi%2Fshell-conduit/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/psibi%2Fshell-conduit/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/psibi%2Fshell-conduit/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/psibi","download_url":"https://codeload.github.com/psibi/shell-conduit/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248103871,"owners_count":21048245,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["conduit","scripting","shell","stream"],"created_at":"2024-08-02T01:03:19.175Z","updated_at":"2025-04-09T20:09:36.305Z","avatar_url":"https://github.com/psibi.png","language":"Haskell","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)\n=====\n\nWrite shell scripts with Conduit. Still in the experimental phase.\n\n[Haddock API documentation](https://www.stackage.org/package/shell-conduit).\n\n### Examples\n\n##### Cloning and initializing a repo\n\n``` haskell\nimport Control.Monad.IO.Class\nimport Data.Conduit.Shell\nimport System.Directory\n\nmain =\n  run (do exists \u003c- liftIO (doesDirectoryExist \"fpco\")\n          if exists\n             then rm \"fpco/.hsenvs\" \"-rf\"\n             else git \"clone\" \"git@github.com:fpco/fpco.git\"\n          liftIO (setCurrentDirectory \"fpco\")\n          shell \"./dev-scripts/update-repo.sh\"\n          shell \"./dev-scripts/build-all.sh\"\n          alertDone)\n```\n\n##### Piping\n\nPiping of processes and normal conduits is possible:\n\n``` haskell\nλ\u003e run (ls $| grep \".*\" $| shell \"cat\" $| conduit (CL.map (S8.map toUpper)))\nDIST\nEXAMPLES\nLICENSE\nREADME.MD\nSETUP.HS\nSHELL-CONDUIT.CABAL\nSRC\nTAGS\nTODO.ORG\n```\n\n##### Running actions in sequence and piping\n\nResults are outputted to stdout unless piped into other processes:\n\n``` haskell\nλ\u003e run (do shell \"echo sup\"; shell \"echo hi\")\nsup\nhi\nλ\u003e run (do shell \"echo sup\" $| sed \"s/u/a/\"; shell \"echo hi\")\nsap\nhi\n```\n\n##### Streaming\n\nLive streaming between pipes like in normal shell scripting is\npossible:\n\n``` haskell\nλ\u003e run (do tail' \"/tmp/example.txt\" \"-f\" $| grep \"--line-buffered\" \"Hello\")\nHello, world!\nOh, hello!\n```\n\n(Remember that `grep` needs `--line-buffered` if it is to output things\nline-by-line).\n\n##### Handling exit failures\n\nProcess errors can be ignored by using the Alternative instance.\n\n``` haskell\nimport Control.Applicative\nimport Control.Monad.Fix\nimport Data.Conduit.Shell\n\nmain =\n  run (do ls\n          echo \"Restarting server ... ?\"\n          killall name \"-q\" \u003c|\u003e return ()\n          fix (\\loop -\u003e\n                 do echo \"Waiting for it to terminate ...\"\n                    sleep \"1\"\n                    (ps \"-C\" name \u003e\u003e loop) \u003c|\u003e return ())\n          shell \"dist/build/ircbrowse/ircbrowse ircbrowse.conf\")\n  where name = \"ircbrowse\"\n```\n\n##### Running custom things\n\nYou can run processes directly:\n\n``` haskell\nλ\u003e run (proc \"ls\" [])\ndist\t  LICENSE    Setup.hs\t\t  src\tTODO.org\nexamples  README.md  shell-conduit.cabal  TAGS\n```\n\nOr shell commands:\n\n``` haskell\nλ\u003e run (shell \"ls\")\ndist\t  LICENSE    Setup.hs\t\t  src\tTODO.org\nexamples  README.md  shell-conduit.cabal  TAGS\n```\n\nOr conduits:\n\n``` haskell\nλ\u003e run (cat $| conduit (awaitForever yield))\nhello\nhello\nInterrupted.\n```\n\n##### Keyboard configuration\n\n``` haskell\nimport Data.Conduit.Shell\nmain =\n  run (do xmodmap \".xmodmap\"\n          xset \"r\" \"rate\" \"150\" \"50\")\n```\n\n### How it works\n\nAll executable names in the `PATH` at compile-time are brought into\nscope as runnable process conduits e.g. `ls` or `grep`.\n\nAll processes are bound as variadic process calling functions, like this:\n\n``` haskell\nrmdir :: ProcessType r =\u003e r\nls :: ProcessType r =\u003e r\n```\n\nBut ultimately the types end up being:\n\n``` haskell\nrmdir \"foo\" :: Segment r\nls :: Segment r\nls \".\" :: Segment r\n```\n\nEtc.\n\nRun all shell scripts with\n\n``` haskell\nrun :: Segment r -\u003e IO r\n```\n\nThe `Segment` type has a handy `Alternative` instance.\n\n### String types\n\nIf using `OverloadedStrings` so that you can use `Text` for arguments,\nthen also enable `ExtendedDefaultRules`, otherwise you'll get\nambiguous type errors.\n\n``` haskell\n{-# LANGUAGE ExtendedDefaultRules #-}\n```\n\nBut this isn't necessary if you don't need to use `Text` yet. Strings\nliterals will be interpreted as `String`. Though you can pass a value\nof type `Text` or any instance of `CmdArg` without needing conversions.\n\n### Other modules\n\nYou might want to import the regular Conduit modules qualified, too:\n\n``` haskell\nimport qualified Data.Conduit.List as CL\n```\n\nWhich contains handy functions for working on streams in a\nlist-like way. See the rest of the handy modules for Conduit in\n[conduit-extra](http://hackage.haskell.org/package/conduit-extra).\n\nAlso of interest is\n[csv-conduit](http://hackage.haskell.org/package/csv-conduit),\n[html-conduit](http://hackage.haskell.org/package/html-conduit), and\n[http-conduit](http://hackage.haskell.org/package/http-conduit).\n\nFinally, see the Conduit category on Hackage for other useful\nlibraries: \u003chttp://hackage.haskell.org/packages/#cat:Conduit\u003e\n\nAll of these general purpose Conduits can be used in shell\nscripting.\n","funding_links":[],"categories":["Haskell"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpsibi%2Fshell-conduit","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpsibi%2Fshell-conduit","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpsibi%2Fshell-conduit/lists"}