https://github.com/luke-clifton/shh Skip to content Toggle navigation Sign up * Product + Actions Automate any workflow + Packages Host and manage packages + Security Find and fix vulnerabilities + Codespaces Instant dev environments + Copilot Write better code with AI + Code review Manage code changes + Issues Plan and track work + Discussions Collaborate outside of code Explore + All features + Documentation + GitHub Skills + Blog * Solutions For + Enterprise + Teams + Startups + Education By Solution + CI/CD & Automation + DevOps + DevSecOps Resources + Learning Pathways + White papers, Ebooks, Webinars + Customer Stories + Partners * Open Source + GitHub Sponsors Fund open source developers + The ReadME Project GitHub community articles Repositories + Topics + Trending + Collections * Pricing Search or jump to... Search code, repositories, users, issues, pull requests... Search [ ] Clear Search syntax tips Provide feedback We read every piece of feedback, and take your input very seriously. [ ] [ ] Include my email address so I can be contacted Cancel Submit feedback Saved searches Use saved searches to filter your results more quickly Name [ ] Query [ ] To see all available qualifiers, see our documentation. Cancel Create saved search Sign in Sign up You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session. You switched accounts on another tab or window. Reload to refresh your session. Dismiss alert {{ message }} luke-clifton / shh Public * Notifications * Fork 9 * Star 183 Simple shell like scripting from Haskell 183 stars 9 forks Activity Star Notifications * Code * Issues 11 * Pull requests 1 * Actions * Projects 0 * Security * Insights Additional navigation options * Code * Issues * Pull requests * Actions * Projects * Security * Insights luke-clifton/shh This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository. master Switch branches/tags [ ] Branches Tags Could not load branches Nothing to show {{ refName }} default View all branches Could not load tags Nothing to show {{ refName }} default View all tags Name already in use A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch? Cancel Create 2 branches 32 tags Code * Local * Codespaces * Clone HTTPS GitHub CLI [https://github.com/l] Use Git or checkout with SVN using the web URL. [gh repo clone luke-c] Work fast with our official CLI. Learn more about the CLI. * Open with GitHub Desktop * Download ZIP Sign In Required Please sign in to use Codespaces. Launching GitHub Desktop If nothing happens, download GitHub Desktop and try again. Launching GitHub Desktop If nothing happens, download GitHub Desktop and try again. Launching Xcode If nothing happens, download Xcode and try again. Launching Visual Studio Code Your codespace will open once ready. There was a problem preparing your codespace, please try again. Latest commit @luke-clifton luke-clifton Fix reference to old function in docs. ... f99538c Aug 28, 2023 Fix reference to old function in docs. fixes #78 f99538c Git stats * 334 commits Files Permalink Failed to load latest commit information. Type Name Latest commit message Commit time .builds Test 9.2.4 August 11, 2022 11:55 docs Recomend PyF as a minimal string interpolation library November 30, 2021 15:23 shh-extras Bump versions and fix deprecation warnings July 17, 2023 11:02 shh Fix reference to old function in docs. August 28, 2023 19:25 .gitignore Cabal Project March 7, 2019 10:49 README.md README tests August 6, 2019 11:04 cabal.project Add shh-extras March 7, 2019 11:27 default.nix Test multiple GHCs December 5, 2021 09:53 release.hs Translate release script to Haskell using Shh. May 29, 2020 15:21 release.sh Typo fix March 10, 2019 10:33 View code [ ] Shh Mnemonics Globbing String Interpolation/Expansion/Substitution Usage Usage in GHCi Shh as a Shell Faster Startup Nix Wrapper Example Script Usage Nix Alternatives Errors README.md Shh [6874747073] [6874747073] [6874747073] Shh is a library to enable convenient shell-like programming in Haskell. It works well in scripts, and from GHCi, allowing you to use GHCi as a shell. {-# LANGUAGE TemplateHaskell #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE ExtendedDefaultRules #-} {-# LANGUAGE QuasiQuotes #-} module Readme (test) where import Shh import System.Environment import Control.Concurrent.Async import Prelude hiding (head) import Test.Tasty import Test.Tasty.HUnit import Test.Tasty.QuickCheck import qualified System.Directory import qualified Data.ByteString.Lazy.Char8 as Char8 import Data.List (nub) import Data.Char import PyF load SearchPath ["echo", "base64", "cat", "head", "sleep", "mktemp", "ls", "wc", "find", "tr", "users", "sha256sum", "false", "true"] curl :: Cmd curl = true test :: IO () test = do It's primary purpose is in replacing shell scripts. As such, many functions are provided to mimic the shell environment, and porting shell scripts to shh should be fairly straightforward. A simple "cargo culting" port should work in most situations, and perhaps be even more robust than the original. It is also a wrapper tool around launching GHCi as a shell. It supports * Automatically defining a function for each executable on your $PATH using template Haskell, as well as a runtime check to ensure they all exist on startup. * Redirection of stdout and stderr -- Redirect stdout echo "Hello" &> StdErr echo "Hello" &> Truncate ".tmp_file" -- Redirect stderr echo "Hello" &!> Append "/dev/null" echo "Hello" &!> StdOut * Piping stdout or stderr to the input of a chained process cat "/dev/urandom" |> base64 |> head "-n" 5 * Multiple processes sequentially feeding a single process (echo 1 >> echo 2) |> cat * Use of Haskell's concurrency primitives. race (sleep 1 >> echo "Slept for 1") (sleep 2 >> echo "Slept for 2") mapConcurrently_ (\url -> curl "-Ls" url |> wc) [ "https://raw.githubusercontent.com/luke-clifton/shh/master/shell.nix" , "https://raw.githubusercontent.com/luke-clifton/shh/master/README.md" ] * Capturing of process output s <- echo "Hello" |> tr "-d" "l" |> capture print s loggedIn <- nub . Char8.words <$> (users |> capture) putStrLn $ "Logged in users: " ++ show loggedIn mapM_ Char8.putStrLn =<< (find "-maxdepth" 1 "-print0" |> captureEndBy0) * Capturing infinite output of a process lazily cat "/dev/urandom" |> base64 |> readInput (mapM_ Char8.putStrLn . take 3 . Char8.lines) * Write strings to stdin of a process. writeOutput "Hello\n" |> cat -- Hello "Hello" >>> sha256sum sha256sum <<< "Hello" * Proper exceptions, when a process exits with a failure code, an exception is thrown. You can catch these normally. The exception includes the error code, the command, and all it's arguments. false "Ha, it died" -- *** Exception: Command `false "Ha, it died"` failed [exit 1] exitCode false -- 1 * "Native" processes, i.e. Haskell functions that behave like a process. echo "Hello" |> pureProc (Char8.map toUpper) |> tr "-d" "L" -- HEO * And much, much more! Look at the documentation on Hackage for a comprehensive overview of all the possibilities. Mnemonics Shh has many symbols that might seem intimidating at first, but there is a simple mnemonic for them. | Piping. Looks like a pipe, same as in POSIX shells. & Redirection, think of the shell `2>&1` >,< The direction of flow of a command ! Operate on stderr instead of stdout So, for example, ls |> cat Pipe the stdout of `ls` into stdin of `cat` cat <| ls Same as above ls &> StdErr Redirect stdout of `ls` to wherever stderr is going. StdErr <& ls Same as above ls &!> StdOut Redirect stderr of `ls` to wherever stdout is going. StdOut