turtle-1.6.2: Shell programming, Haskell-style

Safe Haskell | None
Language | Haskell2010

Turtle.Prelude

Contents

- IO
- Managed
- Shell
- Folds
- Text
- Subprocess management
- Permissions
- File size
- File status
- Headers
- Exceptions

Description

This module provides a large suite of utilities that resemble Unix utilities.

Many of these commands are just existing Haskell commands renamed to match their Unix counterparts:

    >>> :set -XOverloadedStrings
    >>> cd "/tmp"
    >>> pwd
    FilePath "/tmp"

Some commands are `Shell`s that emit streams of values. `view` prints all values in a `Shell` stream:

    >>> view (ls "/usr")
    FilePath "/usr/lib"
    FilePath "/usr/src"
    FilePath "/usr/sbin"
    FilePath "/usr/include"
    FilePath "/usr/share"
    FilePath "/usr/games"
    FilePath "/usr/local"
    FilePath "/usr/bin"
    >>> view (find (suffix "Browser.py") "/usr/lib")
    FilePath "/usr/lib/python3.4/idlelib/ClassBrowser.py"
    FilePath "/usr/lib/python3.4/idlelib/RemoteObjectBrowser.py"
    FilePath "/usr/lib/python3.4/idlelib/PathBrowser.py"
    FilePath "/usr/lib/python3.4/idlelib/ObjectBrowser.py"

Use `fold` to reduce the output of a `Shell` stream:

    >>> import qualified Control.Foldl as Fold
    >>> fold (ls "/usr") Fold.length
    8
    >>> fold (find (suffix "Browser.py") "/usr/lib") Fold.head
    Just (FilePath "/usr/lib/python3.4/idlelib/ClassBrowser.py")

Create files using `output`:

    >>> output "foo.txt" ("123" <|> "456" <|> "ABC")
    >>> realpath "foo.txt"
    FilePath "/tmp/foo.txt"

Read in files using `input`:

    >>> stdout (input "foo.txt")
    123
    456
    ABC

Format strings in a type safe way using `format`:

    >>> dir <- pwd
    >>> format ("I am in the "%fp%" directory") dir
    "I am in the /tmp directory"

Commands like `grep`, `sed` and `find` accept arbitrary `Pattern`s

    >>> stdout (grep ("123" <|> "ABC") (input "foo.txt"))
    123
    ABC
    >>> let exclaim = fmap (<> "!") (plus digit)
    >>> stdout (sed exclaim (input "foo.txt"))
    123!
    456!
    ABC

Note that `grep` and `find` differ from their Unix counterparts by requiring that the `Pattern` matches the entire line or file name by default. However, you can optionally match the prefix, suffix, or interior of a line:

    >>> stdout (grep (has    "2") (input "foo.txt"))
    123
    >>> stdout (grep (prefix "1") (input "foo.txt"))
    123
    >>> stdout (grep (suffix "3") (input "foo.txt"))
    123

You can also build up more sophisticated `Shell` programs using `sh` in conjunction with `do` notation:

    {-# LANGUAGE OverloadedStrings #-}

    import Turtle

    main = sh example

    example = do
        -- Read in file names from "files1.txt" and "files2.txt"
        file <- fmap fromText (input "files1.txt" <|> input "files2.txt")

        -- Stream each file to standard output only if the file exists
        True <- liftIO (testfile file)
        line <- input file
        liftIO (echo line)

See Turtle.Tutorial for an extended tutorial explaining how to use this library in greater detail.

Synopsis

- echo :: MonadIO io => Line -> io ()
- err :: MonadIO io => Line -> io ()
- readline :: MonadIO io => io (Maybe Line)
- readTextFile :: FilePath -> IO Text
- writeTextFile :: FilePath -> Text -> IO ()
- arguments :: MonadIO io => io [Text]
- export :: MonadIO io => Text -> Text -> io ()
- unset :: MonadIO io => Text -> io ()
- need :: MonadIO io => Text -> io (Maybe Text)
- env :: MonadIO io => io [(Text, Text)]
- cd :: MonadIO io => FilePath -> io ()
- pwd :: MonadIO io => io FilePath
- home :: MonadIO io => io FilePath
- readlink :: MonadIO io => FilePath -> io FilePath
- realpath :: MonadIO io => FilePath -> io FilePath
- mv :: MonadIO io => FilePath -> FilePath -> io ()
- mkdir :: MonadIO io => FilePath -> io ()
- mktree :: MonadIO io => FilePath -> io ()
- cp :: MonadIO io => FilePath -> FilePath -> io ()
- cptree :: MonadIO io => FilePath -> FilePath -> io ()
- cptreeL :: MonadIO io => FilePath -> FilePath -> io ()
- symlink :: MonadIO io => FilePath -> FilePath -> io ()
- isNotSymbolicLink :: MonadIO io => FilePath -> io Bool
- rm :: MonadIO io => FilePath -> io ()
- rmdir :: MonadIO io => FilePath -> io ()
- rmtree :: MonadIO io => FilePath -> io ()
- testfile :: MonadIO io => FilePath -> io Bool
- testdir :: MonadIO io => FilePath -> io Bool
- testpath :: MonadIO io => FilePath -> io Bool
- date :: MonadIO io => io UTCTime
- datefile :: MonadIO io => FilePath -> io UTCTime
- touch :: MonadIO io => FilePath -> io ()
- time :: MonadIO io => io a -> io (a, NominalDiffTime)
- hostname :: MonadIO io => io Text
- which :: MonadIO io => FilePath -> io (Maybe FilePath)
- whichAll :: FilePath -> Shell FilePath
- sleep :: MonadIO io => NominalDiffTime -> io ()
- exit :: MonadIO io => ExitCode -> io a
- die :: MonadIO io => Text -> io a
- (.&&.) :: Monad m => m ExitCode -> m ExitCode -> m ExitCode
- (.||.) :: Monad m => m ExitCode -> m ExitCode -> m ExitCode
- readonly :: MonadManaged managed => FilePath -> managed Handle
- writeonly :: MonadManaged managed => FilePath -> managed Handle
- appendonly :: MonadManaged managed => FilePath -> managed Handle
- mktemp :: MonadManaged managed => FilePath -> Text -> managed (FilePath, Handle)
- mktempfile :: MonadManaged managed => FilePath -> Text -> managed FilePath
- mktempdir :: MonadManaged managed => FilePath -> Text -> managed FilePath
- fork :: MonadManaged managed => IO a -> managed (Async a)
- wait :: MonadIO io => Async a -> io a
- pushd :: MonadManaged managed => FilePath -> managed ()
- stdin :: Shell Line
- input :: FilePath -> Shell Line
- inhandle :: Handle -> Shell Line
- stdout :: MonadIO io => Shell Line -> io ()
- output :: MonadIO io => FilePath -> Shell Line -> io ()
- outhandle :: MonadIO io => Handle -> Shell Line -> io ()
- append :: MonadIO io => FilePath -> Shell Line -> io ()
- stderr :: MonadIO io => Shell Line -> io ()
- strict :: MonadIO io => Shell Line -> io Text
- ls :: FilePath -> Shell FilePath
- lsif :: (FilePath -> IO Bool) -> FilePath -> Shell FilePath
- lstree :: FilePath -> Shell FilePath
- lsdepth :: Int -> Int -> FilePath -> Shell FilePath
- cat :: [Shell a] -> Shell a
- grep :: Pattern a -> Shell Line -> Shell Line
- grepText :: Pattern a -> Shell Text -> Shell Text
- sed :: Pattern Text -> Shell Line -> Shell Line
- sedPrefix :: Pattern Text -> Shell Line -> Shell Line
- sedSuffix :: Pattern Text -> Shell Line -> Shell Line
- sedEntire :: Pattern Text -> Shell Line -> Shell Line
- onFiles :: (Shell Text -> Shell Text) -> Shell FilePath -> Shell FilePath
- inplace :: MonadIO io => Pattern Text -> FilePath -> io ()
- inplacePrefix :: MonadIO io => Pattern Text -> FilePath -> io ()
- inplaceSuffix :: MonadIO io => Pattern Text -> FilePath -> io ()
- inplaceEntire :: MonadIO io => Pattern Text -> FilePath -> io ()
- update :: MonadIO io => (Shell Line -> Shell Line) -> FilePath -> io ()
- find :: Pattern a -> FilePath -> Shell FilePath
- findtree :: Pattern a -> Shell FilePath -> Shell FilePath
- yes :: Shell Line
- nl :: Num n => Shell a -> Shell (n, a)
- paste :: Shell a -> Shell b -> Shell (a, b)
- endless :: Shell ()
- limit :: Int -> Shell a -> Shell a
- limitWhile :: (a -> Bool) -> Shell a -> Shell a
- cache :: (Read a, Show a) => FilePath -> Shell a -> Shell a
- parallel :: [IO a] -> Shell a
- single :: MonadIO io => Shell a -> io a
- uniq :: Eq a => Shell a -> Shell a
- uniqOn :: Eq b => (a -> b) -> Shell a -> Shell a
- uniqBy :: (a -> a -> Bool) -> Shell a -> Shell a
- nub :: Ord a => Shell a -> Shell a
- nubOn :: Ord b => (a -> b) -> Shell a -> Shell a
- sort :: (Functor io, MonadIO io, Ord a) => Shell a -> io [a]
- sortOn :: (Functor io, MonadIO io, Ord b) => (a -> b) -> Shell a -> io [a]
- sortBy :: (Functor io, MonadIO io) => (a -> a -> Ordering) -> Shell a -> io [a]
- toLines :: Shell Text -> Shell Line
- countChars :: Integral n => Fold Line n
- countWords :: Integral n => Fold Line n
- countLines :: Integral n => Fold Line n
- cut :: Pattern a -> Text -> [Text]
- proc :: MonadIO io => Text -> [Text] -> Shell Line -> io ExitCode
- shell :: MonadIO io => Text -> Shell Line -> io ExitCode
- procs :: MonadIO io => Text -> [Text] -> Shell Line -> io ()
- shells :: MonadIO io => Text -> Shell Line -> io ()
- inproc :: Text -> [Text] -> Shell Line -> Shell Line
- inshell :: Text -> Shell Line -> Shell Line
- inprocWithErr :: Text -> [Text] -> Shell Line -> Shell (Either Line Line)
- inshellWithErr :: Text -> Shell Line -> Shell (Either Line Line)
- procStrict :: MonadIO io => Text -> [Text] -> Shell Line -> io (ExitCode, Text)
- shellStrict :: MonadIO io => Text -> Shell Line -> io (ExitCode, Text)
- procStrictWithErr :: MonadIO io => Text -> [Text] -> Shell Line -> io (ExitCode, Text, Text)
- shellStrictWithErr :: MonadIO io => Text -> Shell Line -> io (ExitCode, Text, Text)
- system :: MonadIO io => CreateProcess -> Shell Line -> io ExitCode
- stream :: CreateProcess -> Shell Line -> Shell Line
- streamWithErr :: CreateProcess -> Shell Line -> Shell (Either Line Line)
- systemStrict :: MonadIO io => CreateProcess -> Shell Line -> io (ExitCode, Text)
- systemStrictWithErr :: MonadIO io => CreateProcess -> Shell Line -> io (ExitCode, Text, Text)
- data Permissions = Permissions {
  - _readable :: Bool
  - _writable :: Bool
  - _executable :: Bool
  }
- chmod :: MonadIO io => (Permissions -> Permissions) -> FilePath -> io Permissions
- getmod :: MonadIO io => FilePath -> io Permissions
- setmod :: MonadIO io => Permissions -> FilePath -> io ()
- copymod :: MonadIO io => FilePath -> FilePath -> io ()
- readable :: Permissions -> Permissions
- nonreadable :: Permissions -> Permissions
- writable :: Permissions -> Permissions
- nonwritable :: Permissions -> Permissions
- executable :: Permissions -> Permissions
- nonexecutable :: Permissions -> Permissions
- ooo :: Permissions -> Permissions
- roo :: Permissions -> Permissions
- owo :: Permissions -> Permissions
- oox :: Permissions -> Permissions
- rwo :: Permissions -> Permissions
- rox :: Permissions -> Permissions
- owx :: Permissions -> Permissions
- rwx :: Permissions -> Permissions
- du :: MonadIO io => FilePath -> io Size
- data Size where
  - pattern B :: Integral n => n -> Size
  - pattern KB :: Integral n => n -> Size
  - pattern MB :: Integral n => n -> Size
  - pattern GB :: Integral n => n -> Size
  - pattern TB :: Integral n => n -> Size
  - pattern KiB :: Integral n => n -> Size
  - pattern MiB :: Integral n => n -> Size
  - pattern GiB :: Integral n => n -> Size
  - pattern TiB :: Integral n => n -> Size
- sz :: Format r (Size -> r)
- bytes :: Integral n => Size -> n
- kilobytes :: Integral n => Size -> n
- megabytes :: Integral n => Size -> n
- gigabytes :: Integral n => Size -> n
- terabytes :: Integral n => Size -> n
- kibibytes :: Integral n => Size -> n
- mebibytes :: Integral n => Size -> n
- gibibytes :: Integral n => Size -> n
- tebibytes :: Integral n => Size -> n
- data FileStatus
- stat :: MonadIO io => FilePath -> io FileStatus
- lstat :: MonadIO io => FilePath -> io FileStatus
- fileSize :: FileStatus -> Size
- accessTime :: FileStatus -> POSIXTime
- modificationTime :: FileStatus -> POSIXTime
- statusChangeTime :: FileStatus -> POSIXTime
- isBlockDevice :: FileStatus -> Bool
- isCharacterDevice :: FileStatus -> Bool
- isNamedPipe :: FileStatus -> Bool
- isRegularFile :: FileStatus -> Bool
- isDirectory :: FileStatus -> Bool
- isSymbolicLink :: FileStatus -> Bool
- isSocket :: FileStatus -> Bool
- cmin :: MonadIO io => UTCTime -> FilePath -> io Bool
- cmax :: MonadIO io => UTCTime -> FilePath -> io Bool
- data WithHeader a
  - = Header a
  - | Row a a
- header :: Shell a -> Shell (WithHeader a)
- data ProcFailed = ProcFailed {
  - procCommand :: Text
  - procArguments :: [Text]
  - procExitCode :: ExitCode
  }
- data ShellFailed = ShellFailed {
  - shellCommandLine :: Text
  - shellExitCode :: ExitCode
  }

# IO

echo :: MonadIO io => Line -> io () #

Print exactly one line to `stdout`

To print more than one line see `printf`, which also supports formatted output

err :: MonadIO io => Line -> io () #

Print exactly one line to `stderr`

readline :: MonadIO io => io (Maybe Line) #

Read in a line from `stdin`

Returns `Nothing` if at end of input

readTextFile :: FilePath -> IO Text #

Deprecated: Use Data.Text.IO.readFile instead

Read in a file as `Text`

writeTextFile :: FilePath -> Text -> IO () #

Deprecated: Use Data.Text.IO.writeFile instead

Write out a file as `Text`

arguments :: MonadIO io => io [Text] #

Get command line arguments in a list

export :: MonadIO io => Text -> Text -> io () #

Set or modify an environment variable

Note: This will change the current environment for all of your program's threads since this modifies the global state of the process

unset :: MonadIO io => Text -> io () #

Delete an environment variable

need :: MonadIO io => Text -> io (Maybe Text) #

Look up an environment variable

env :: MonadIO io => io [(Text, Text)] #

Retrieve all environment variables

cd :: MonadIO io => FilePath -> io () #

Change the current directory

Note: This will change the current directory for all of your program's threads since this modifies the global state of the process

pwd :: MonadIO io => io FilePath #

Get the current directory

home :: MonadIO io => io FilePath #

Get the home directory

readlink :: MonadIO io => FilePath -> io FilePath #

Get the path pointed to by a symlink

realpath :: MonadIO io => FilePath -> io FilePath #

Canonicalize a path

mv :: MonadIO io => FilePath -> FilePath -> io () #

Move a file or directory

Works if the two paths are on the same filesystem. If not, `mv` will still work when dealing with a regular file, but the operation will not be atomic

mkdir :: MonadIO io => FilePath -> io () #

Create a directory

Fails if the directory is present

mktree :: MonadIO io => FilePath -> io () #

Create a directory tree (equivalent to `mkdir -p`)

Does not fail if the directory is present

cp :: MonadIO io => FilePath -> FilePath -> io () #

Copy a file

cptree :: MonadIO io => FilePath -> FilePath -> io () #

Copy a directory tree and preserve symbolic links

cptreeL :: MonadIO io => FilePath -> FilePath -> io () #

Copy a directory tree and dereference symbolic links

symlink :: MonadIO io => FilePath -> FilePath -> io () #

Create a symlink from one `FilePath` to another

isNotSymbolicLink :: MonadIO io => FilePath -> io Bool #

Returns `True` if the given `FilePath` is not a symbolic link

This comes in handy in conjunction with `lsif`:

    lsif isNotSymbolicLink

rm :: MonadIO io => FilePath -> io () #

Remove a file

rmdir :: MonadIO io => FilePath -> io () #

Remove a directory

rmtree :: MonadIO io => FilePath -> io () #

Remove a directory tree (equivalent to `rm -r`)

Use at your own risk

testfile :: MonadIO io => FilePath -> io Bool #

Check if a file exists

testdir :: MonadIO io => FilePath -> io Bool #

Check if a directory exists

testpath :: MonadIO io => FilePath -> io Bool #

Check if a path exists

date :: MonadIO io => io UTCTime #

Get the current time

datefile :: MonadIO io => FilePath -> io UTCTime #

Get the time a file was last modified

touch :: MonadIO io => FilePath -> io () #

Touch a file, updating the access and modification times to the current time

Creates an empty file if it does not exist

time :: MonadIO io => io a -> io (a, NominalDiffTime) #

Time how long a command takes in monotonic wall clock time

Returns the duration alongside the return value

hostname :: MonadIO io => io Text #

Get the system's host name

which :: MonadIO io => FilePath -> io (Maybe FilePath) #

Show the full path of an executable file

whichAll :: FilePath -> Shell FilePath #

Show all matching executables in PATH, not just the first

sleep :: MonadIO io => NominalDiffTime -> io () #

Sleep for the given duration

A numeric literal argument is interpreted as seconds. In other words, `(sleep 2.0)` will sleep for two seconds.

exit :: MonadIO io => ExitCode -> io a #

Exit with the given exit code

An exit code of `0` indicates success

die :: MonadIO io => Text -> io a #

Throw an exception using the provided `Text` message

(.&&.) :: Monad m => m ExitCode -> m ExitCode -> m ExitCode infixr 3 #

Analogous to `&&` in Bash

Runs the second command only if the first one returns `ExitSuccess`

(.||.) :: Monad m => m ExitCode -> m ExitCode -> m ExitCode infixr 2 #

Analogous to `||` in Bash

Run the second command only if the first one returns `ExitFailure`

# Managed

readonly :: MonadManaged managed => FilePath -> managed Handle #

Acquire a `Managed` read-only `Handle` from a `FilePath`

writeonly :: MonadManaged managed => FilePath -> managed Handle #

Acquire a `Managed` write-only `Handle` from a `FilePath`

appendonly :: MonadManaged managed => FilePath -> managed Handle #

Acquire a `Managed` append-only `Handle` from a `FilePath`

mktemp #

Arguments

:: MonadManaged managed |
=> FilePath | Parent directory
-> Text | File name template
-> managed (FilePath, Handle) |

Create a temporary file underneath the given directory

Deletes the temporary file when done

Note that this provides the `Handle` of the file in order to avoid a potential race condition from the file being moved or deleted before you have a chance to open the file. The `mktempfile` function provides a simpler API if you don't need to worry about that possibility.

mktempfile #

Arguments

:: MonadManaged managed |
=> FilePath | Parent directory
-> Text | File name template
-> managed FilePath |

Create a temporary file underneath the given directory

Deletes the temporary file when done

mktempdir #

Arguments

:: MonadManaged managed |
=> FilePath | Parent directory
-> Text | Directory name template
-> managed FilePath |

Create a temporary directory underneath the given directory

Deletes the temporary directory when done

fork :: MonadManaged managed => IO a -> managed (Async a) #

Fork a thread, acquiring an `Async` value

wait :: MonadIO io => Async a -> io a #

Wait for an `Async` action to complete

pushd :: MonadManaged managed => FilePath -> managed () #

Change the current directory. Once the current `Shell` is done, it returns back to the original directory.

    >>> :set -XOverloadedStrings
    >>> cd "/"
    >>> view (pushd "/tmp" >> pwd)
    FilePath "/tmp"
    >>> pwd
    FilePath "/"

# Shell

stdin :: Shell Line #

Read lines of `Text` from standard input

input :: FilePath -> Shell Line #

Read lines of `Text` from a file

inhandle :: Handle -> Shell Line #

Read lines of `Text` from a `Handle`

stdout :: MonadIO io => Shell Line -> io () #

Stream lines of `Text` to standard output

output :: MonadIO io => FilePath -> Shell Line -> io () #

Stream lines of `Text` to a file

outhandle :: MonadIO io => Handle -> Shell Line -> io () #

Stream lines of `Text` to a `Handle`

append :: MonadIO io => FilePath -> Shell Line -> io () #

Stream lines of `Text` to append to a file

stderr :: MonadIO io => Shell Line -> io () #

Stream lines of `Text` to standard error

strict :: MonadIO io => Shell Line -> io Text #

Read in a stream's contents strictly

ls :: FilePath -> Shell FilePath #

Stream all immediate children of the given directory, excluding `"."` and `".."`

lsif :: (FilePath -> IO Bool) -> FilePath -> Shell FilePath #

Stream all recursive descendents of the given directory

This skips any directories that fail the supplied predicate

    lstree = lsif (\_ -> return True)

lstree :: FilePath -> Shell FilePath #

Stream all recursive descendents of the given directory

lsdepth :: Int -> Int -> FilePath -> Shell FilePath #

Stream the recursive descendents of a given directory between a given minimum and maximum depth

cat :: [Shell a] -> Shell a #

Combine the output of multiple `Shell`s, in order

grep :: Pattern a -> Shell Line -> Shell Line #

Keep all lines that match the given `Pattern`

grepText :: Pattern a -> Shell Text -> Shell Text #

Keep every `Text` element that matches the given `Pattern`

sed :: Pattern Text -> Shell Line -> Shell Line #

Replace all occurrences of a `Pattern` with its `Text` result

`sed` performs substitution on a line-by-line basis, meaning that substitutions may not span multiple lines. Additionally, substitutions may occur multiple times within the same line, like the behavior of `s/.../.../g`.

Warning: Do not use a `Pattern` that matches the empty string, since it will match an infinite number of times. `sed` tries to detect such `Pattern`s and `die` with an error message if they occur, but this detection is necessarily incomplete.

sedPrefix :: Pattern Text -> Shell Line -> Shell Line #

Like `sed`, but the provided substitution must match the beginning of the line

sedSuffix :: Pattern Text -> Shell Line -> Shell Line #

Like `sed`, but the provided substitution must match the end of the line

sedEntire :: Pattern Text -> Shell Line -> Shell Line #

Like `sed`, but the provided substitution must match the entire line

onFiles :: (Shell Text -> Shell Text) -> Shell FilePath -> Shell FilePath #

Make a `Shell Text -> Shell Text` function work on `FilePath`s instead. | Ignores any paths which cannot be decoded as valid `Text`.

inplace :: MonadIO io => Pattern Text -> FilePath -> io () #

Like `sed`, but operates in place on a `FilePath` (analogous to `sed -i`)

inplacePrefix :: MonadIO io => Pattern Text -> FilePath -> io () #

Like `sedPrefix`, but operates in place on a `FilePath`

inplaceSuffix :: MonadIO io => Pattern Text -> FilePath -> io () #

Like `sedSuffix`, but operates in place on a `FilePath`

inplaceEntire :: MonadIO io => Pattern Text -> FilePath -> io () #

Like `sedEntire`, but operates in place on a `FilePath`

update :: MonadIO io => (Shell Line -> Shell Line) -> FilePath -> io () #

Update a file in place using a `Shell` transformation

For example, this is used to implement the `inplace*` family of utilities

find :: Pattern a -> FilePath -> Shell FilePath #

Search a directory recursively for all files matching the given `Pattern`

findtree :: Pattern a -> Shell FilePath -> Shell FilePath #

Filter a shell of FilePaths according to a given pattern

yes :: Shell Line #

A Stream of `"y"`s

nl :: Num n => Shell a -> Shell (n, a) #

Number each element of a `Shell` (starting at 0)

paste :: Shell a -> Shell b -> Shell (a, b) #

Merge two `Shell`s together, element-wise

If one `Shell` is longer than the other, the excess elements are truncated

endless :: Shell () #

A `Shell` that endlessly emits `()`

limit :: Int -> Shell a -> Shell a #

Limit a `Shell` to a fixed number of values

NOTE: This is not lazy and will still consume the entire input stream. There is no way to implement a lazy version of this utility.

limitWhile :: (a -> Bool) -> Shell a -> Shell a #

Limit a `Shell` to values that satisfy the predicate

This terminates the stream on the first value that does not satisfy the predicate

cache :: (Read a, Show a) => FilePath -> Shell a -> Shell a #

Cache a `Shell`'s output so that repeated runs of the script will reuse the result of previous runs. You must supply a `FilePath` where the cached result will be stored.

The stored result is only reused if the `Shell` successfully ran to completion without any exceptions. Note: on some platforms Ctrl-C will flush standard input and signal end of file before killing the program, which may trick the program into "successfully" completing.

parallel :: [IO a] -> Shell a #

Run a list of IO actions in parallel using fork and wait.

    >>> view (parallel [(sleep 3) >> date, date, date])
    2016-12-01 17:22:10.83296 UTC
    2016-12-01 17:22:07.829876 UTC
    2016-12-01 17:22:07.829963 UTC

single :: MonadIO io => Shell a -> io a #

Returns the result of a `Shell` that outputs a single line. Note that if no lines / more than 1 line is produced by the Shell, this function will `die` with an error message.

    main = do
      directory <- single (inshell "pwd" empty)
      print directory

uniq :: Eq a => Shell a -> Shell a #

Filter adjacent duplicate elements:

    >>> view (uniq (select [1,1,2,1,3]))
    1
    2
    1
    3

uniqOn :: Eq b => (a -> b) -> Shell a -> Shell a #

Filter adjacent duplicates determined after applying the function to the element:

    >>> view (uniqOn fst (select [(1,'a'),(1,'b'),(2,'c'),(1,'d'),(3,'e')]))
    (1,'a')
    (2,'c')
    (1,'d')
    (3,'e')

uniqBy :: (a -> a -> Bool) -> Shell a -> Shell a #

Filter adjacent duplicate elements determined via the given function:

    >>> view (uniqBy (==) (select [1,1,2,1,3]))
    1
    2
    1
    3

nub :: Ord a => Shell a -> Shell a #

Return a new `Shell` that discards duplicates from the input `Shell`:

    >>> view (nub (select [1, 1, 2, 3, 3, 4, 3]))
    1
    2
    3
    4

nubOn :: Ord b => (a -> b) -> Shell a -> Shell a #

Return a new `Shell` that discards duplicates determined via the given function from the input `Shell`:

    >>> view (nubOn id (select [1, 1, 2, 3, 3, 4, 3]))
    1
    2
    3
    4

sort :: (Functor io, MonadIO io, Ord a) => Shell a -> io [a] #

Return a list of the sorted elements of the given `Shell`, keeping duplicates:

    >>> sort (select [1,4,2,3,3,7])
    [1,2,3,3,4,7]

sortOn :: (Functor io, MonadIO io, Ord b) => (a -> b) -> Shell a -> io [a] #

Return a list of the elements of the given `Shell`, sorted after applying the given function and keeping duplicates:

    >>> sortOn id (select [1,4,2,3,3,7])
    [1,2,3,3,4,7]

sortBy :: (Functor io, MonadIO io) => (a -> a -> Ordering) -> Shell a -> io [a] #

Return a list of the elements of the given `Shell`, sorted by the given function and keeping duplicates:

    >>> sortBy (comparing fst) (select [(1,'a'),(4,'b'),(2,'c'),(3,'d'),(3,'e'),(7,'f')])
    [(1,'a'),(2,'c'),(3,'d'),(3,'e'),(4,'b'),(7,'f')]

toLines :: Shell Text -> Shell Line #

Group an arbitrary stream of `Text` into newline-delimited `Line`s

    >>> stdout (toLines ("ABC" <|> "DEF" <|> "GHI")
    ABCDEFGHI
    >>> stdout (toLines empty)  -- Note that this always emits at least 1 `Line`

    >>> stdout (toLines ("ABC\nDEF" <|> "" <|> "GHI\nJKL"))
    ABC
    DEFGHI
    JKL

# Folds

countChars :: Integral n => Fold Line n #

Count the number of characters in the stream (like `wc -c`)

This uses the convention that the elements of the stream are implicitly ended by newlines that are one character wide

countWords :: Integral n => Fold Line n #

Count the number of words in the stream (like `wc -w`)

countLines :: Integral n => Fold Line n #

Count the number of lines in the stream (like `wc -l`)

This uses the convention that each element of the stream represents one line

# Text

cut :: Pattern a -> Text -> [Text] #

Split a line into chunks delimited by the given `Pattern`

# Subprocess management

proc #

Arguments

:: MonadIO io |
=> Text | Command
-> [Text] | Arguments
-> Shell Line | Lines of standard input
-> io ExitCode | Exit code

Run a command using `execvp`, retrieving the exit code

The command inherits `stdout` and `stderr` for the current process

shell #

Arguments

:: MonadIO io |
=> Text | Command line
-> Shell Line | Lines of standard input
-> io ExitCode | Exit code

Run a command line using the shell, retrieving the exit code

This command is more powerful than `proc`, but highly vulnerable to code injection if you template the command line with untrusted input

The command inherits `stdout` and `stderr` for the current process

procs #

Arguments

:: MonadIO io |
=> Text | Command
-> [Text] | Arguments
-> Shell Line | Lines of standard input
-> io () |

This function is identical to `proc` except this throws `ProcFailed` for non-zero exit codes

shells #

Arguments

:: MonadIO io |
=> Text | Command line
-> Shell Line | Lines of standard input
-> io () | Exit code

This function is identical to `shell` except this throws `ShellFailed` for non-zero exit codes

inproc #

Arguments

:: Text | Command
-> [Text] | Arguments
-> Shell Line | Lines of standard input
-> Shell Line | Lines of standard output

Run a command using `execvp`, streaming `stdout` as lines of `Text`

The command inherits `stderr` for the current process

inshell #

Arguments

:: Text | Command line
-> Shell Line | Lines of standard input
-> Shell Line | Lines of standard output

Run a command line using the shell, streaming `stdout` as lines of `Text`

This command is more powerful than `inproc`, but highly vulnerable to code injection if you template the command line with untrusted input

The command inherits `stderr` for the current process

Throws an `ExitCode` exception if the command returns a non-zero exit code

inprocWithErr #

Arguments

:: Text | Command
-> [Text] | Arguments
-> Shell Line | Lines of standard input
-> Shell (Either Line Line) | Lines of either standard output (`Right`) or standard error (`Left`)

Run a command using the shell, streaming `stdout` and `stderr` as lines of `Text`. Lines from `stdout` are wrapped in `Right` and lines from `stderr` are wrapped in `Left`.

Throws an `ExitCode` exception if the command returns a non-zero exit code

inshellWithErr #

Arguments

:: Text | Command line
-> Shell Line | Lines of standard input
-> Shell (Either Line Line) | Lines of either standard output (`Right`) or standard error (`Left`)

Run a command line using the shell, streaming `stdout` and `stderr` as lines of `Text`. Lines from `stdout` are wrapped in `Right` and lines from `stderr` are wrapped in `Left`.

This command is more powerful than `inprocWithErr`, but highly vulnerable to code injection if you template the command line with untrusted input

Throws an `ExitCode` exception if the command returns a non-zero exit code

procStrict #

Arguments

:: MonadIO io |
=> Text | Command
-> [Text] | Arguments
-> Shell Line | Lines of standard input
-> io (ExitCode, Text) | Exit code and stdout

Run a command using `execvp`, retrieving the exit code and stdout as a non-lazy blob of Text

The command inherits `stderr` for the current process

shellStrict #

Arguments

:: MonadIO io |
=> Text | Command line
-> Shell Line | Lines of standard input
-> io (ExitCode, Text) | Exit code and stdout

Run a command line using the shell, retrieving the exit code and stdout as a non-lazy blob of Text

This command is more powerful than `proc`, but highly vulnerable to code injection if you template the command line with untrusted input

The command inherits `stderr` for the current process

procStrictWithErr #

Arguments

:: MonadIO io |
=> Text | Command
-> [Text] | Arguments
-> Shell Line | Lines of standard input
-> io (ExitCode, Text, Text) | (Exit code, stdout, stderr)

Run a command using `execvp`, retrieving the exit code, stdout, and stderr as a non-lazy blob of Text

shellStrictWithErr #

Arguments

:: MonadIO io |
=> Text | Command line
-> Shell Line | Lines of standard input
-> io (ExitCode, Text, Text) | (Exit code, stdout, stderr)

Run a command line using the shell, retrieving the exit code, stdout, and stderr as a non-lazy blob of Text

This command is more powerful than `proc`, but highly vulnerable to code injection if you template the command line with untrusted input

system #

Arguments

:: MonadIO io |
=> CreateProcess | Command
-> Shell Line | Lines of standard input
-> io ExitCode | Exit code

`system` generalizes `shell` and `proc` by allowing you to supply your own custom `CreateProcess`. This is for advanced users who feel comfortable using the lower-level `process` API

stream #

Arguments

:: CreateProcess | Command
-> Shell Line | Lines of standard input
-> Shell Line | Lines of standard output

`stream` generalizes `inproc` and `inshell` by allowing you to supply your own custom `CreateProcess`. This is for advanced users who feel comfortable using the lower-level `process` API

Throws an `ExitCode` exception if the command returns a non-zero exit code

streamWithErr #

Arguments

:: CreateProcess | Command
-> Shell Line | Lines of standard input
-> Shell (Either Line Line) | Lines of standard output

`streamWithErr` generalizes `inprocWithErr` and `inshellWithErr` by allowing you to supply your own custom `CreateProcess`. This is for advanced users who feel comfortable using the lower-level `process` API

Throws an `ExitCode` exception if the command returns a non-zero exit code

systemStrict #

Arguments

:: MonadIO io |
=> CreateProcess | Command
-> Shell Line | Lines of standard input
-> io (ExitCode, Text) | Exit code and stdout

`systemStrict` generalizes `shellStrict` and `procStrict` by allowing you to supply your own custom `CreateProcess`. This is for advanced users who feel comfortable using the lower-level `process` API

systemStrictWithErr #

Arguments

:: MonadIO io |
=> CreateProcess | Command
-> Shell Line | Lines of standard input
-> io (ExitCode, Text, Text) | Exit code and stdout

`systemStrictWithErr` generalizes `shellStrictWithErr` and `procStrictWithErr` by allowing you to supply your own custom `CreateProcess`. This is for advanced users who feel comfortable using the lower-level `process` API

# Permissions

data Permissions #

This type is the same as `System.Directory.`Permissions`` type except combining the `executable` and `searchable` fields into a single `executable` field for consistency with the Unix `chmod`. This simplification is still entirely consistent with the behavior of System.Directory, which treats the two fields as interchangeable.

Constructors

Permissions |
Fields _readable :: Bool _writable :: Bool _executable :: Bool

#### Instances

Instances details

Read Permissions # |
Instance details Defined in Turtle.Prelude Methods readsPrec :: Int -> ReadS Permissions # readList :: ReadS [Permissions] # readPrec :: ReadPrec Permissions # readListPrec :: ReadPrec [Permissions] #
Show Permissions # |
Instance details Defined in Turtle.Prelude Methods showsPrec :: Int -> Permissions -> ShowS # show :: Permissions -> String # showList :: [Permissions] -> ShowS #
Eq Permissions # |
Instance details Defined in Turtle.Prelude Methods (==) :: Permissions -> Permissions -> Bool # (/=) :: Permissions -> Permissions -> Bool #
Ord Permissions # |
Instance details Defined in Turtle.Prelude Methods compare :: Permissions -> Permissions -> Ordering # (<) :: Permissions -> Permissions -> Bool # (<=) :: Permissions -> Permissions -> Bool # (>) :: Permissions -> Permissions -> Bool # (>=) :: Permissions -> Permissions -> Bool # max :: Permissions -> Permissions -> Permissions # min :: Permissions -> Permissions -> Permissions #

chmod #

Arguments

:: MonadIO io |
=> (Permissions -> Permissions) | Permissions update function
-> FilePath | Path
-> io Permissions | Updated permissions

Update a file or directory's user permissions

    chmod rwo         "foo.txt"  -- chmod u=rw foo.txt
    chmod executable  "foo.txt"  -- chmod u+x foo.txt
    chmod nonwritable "foo.txt"  -- chmod u-w foo.txt

The meaning of each permission is:

- `readable` (`+r` for short): For files, determines whether you can read from that file (such as with `input`). For directories, determines whether or not you can list the directory contents (such as with `ls`). Note: if a directory is not readable then `ls` will stream an empty list of contents
- `writable` (`+w` for short): For files, determines whether you can write to that file (such as with `output`). For directories, determines whether you can create a new file underneath that directory.
- `executable` (`+x` for short): For files, determines whether or not that file is executable (such as with `proc`). For directories, determines whether or not you can read or execute files underneath that directory (such as with `input` or `proc`)

getmod :: MonadIO io => FilePath -> io Permissions #

Get a file or directory's user permissions

setmod :: MonadIO io => Permissions -> FilePath -> io () #

Set a file or directory's user permissions

copymod :: MonadIO io => FilePath -> FilePath -> io () #

Copy a file or directory's permissions (analogous to `chmod --reference`)

readable :: Permissions -> Permissions #

    +r

nonreadable :: Permissions -> Permissions #

    -r

writable :: Permissions -> Permissions #

    +w

nonwritable :: Permissions -> Permissions #

    -w

executable :: Permissions -> Permissions #

    +x

nonexecutable :: Permissions -> Permissions #

    -x

ooo :: Permissions -> Permissions #

    -r -w -x

roo :: Permissions -> Permissions #

    +r -w -x

owo :: Permissions -> Permissions #

    -r +w -x

oox :: Permissions -> Permissions #

    -r -w +x

rwo :: Permissions -> Permissions #

    +r +w -x

rox :: Permissions -> Permissions #

    +r -w +x

owx :: Permissions -> Permissions #

    -r +w +x

rwx :: Permissions -> Permissions #

    +r +w +x

# File size

du :: MonadIO io => FilePath -> io Size #

Get the size of a file or a directory

data Size where #

An abstract file size

Specify the units you want by using an accessor like `kilobytes`

The `Num` instance for `Size` interprets numeric literals as bytes

Bundled Patterns

pattern B :: Integral n => n -> Size | Construct a `Size` from an integer in bytes
    >>> format sz (B 42)
    "42 B"
pattern KB :: Integral n => n -> Size | Construct a `Size` from an integer in kilobytes
    >>> format sz (KB 42)
    "42.0 KB"
    >>> let B n = KB 1 in n
    1000
pattern MB :: Integral n => n -> Size | Construct a `Size` from an integer in megabytes
    >>> format sz (MB 42)
    "42.0 MB"
    >>> let KB n = MB 1 in n
    1000
pattern GB :: Integral n => n -> Size | Construct a `Size` from an integer in gigabytes
    >>> format sz (GB 42)
    "42.0 GB"
    >>> let MB n = GB 1 in n
    1000
pattern TB :: Integral n => n -> Size | Construct a `Size` from an integer in terabytes
    >>> format sz (TB 42)
    "42.0 TB"
    >>> let GB n = TB 1 in n
    1000
pattern KiB :: Integral n => n -> Size | Construct a `Size` from an integer in kibibytes
    >>> format sz (KiB 42)
    "43.8 KB"
    >>> let B n = KiB 1 in n
    1024
pattern MiB :: Integral n => n -> Size | Construct a `Size` from an integer in mebibytes
    >>> format sz (MiB 42)
    "44.40 MB"
    >>> let KiB n = MiB 1 in n
    1024
pattern GiB :: Integral n => n -> Size | Construct a `Size` from an integer in gibibytes
    >>> format sz (GiB 42)
    "45.97 GB"
    >>> let MiB n = GiB 1 in n
    1024
pattern TiB :: Integral n => n -> Size | Construct a `Size` from an integer in tebibytes
    >>> format sz (TiB 42)
    "46.179 TB"
    >>> let GiB n = TiB 1 in n
    1024

#### Instances

Instances details

Num Size # |
Instance details Defined in Turtle.Prelude Methods (+) :: Size -> Size -> Size # (-) :: Size -> Size -> Size # (*) :: Size -> Size -> Size # negate :: Size -> Size # abs :: Size -> Size # signum :: Size -> Size # fromInteger :: Integer -> Size #
Show Size # |
Instance details Defined in Turtle.Prelude Methods showsPrec :: Int -> Size -> ShowS # show :: Size -> String # showList :: [Size] -> ShowS #
Eq Size # |
Instance details Defined in Turtle.Prelude Methods (==) :: Size -> Size -> Bool # (/=) :: Size -> Size -> Bool #
Ord Size # |
Instance details Defined in Turtle.Prelude Methods compare :: Size -> Size -> Ordering # (<) :: Size -> Size -> Bool # (<=) :: Size -> Size -> Bool # (>) :: Size -> Size -> Bool # (>=) :: Size -> Size -> Bool # max :: Size -> Size -> Size # min :: Size -> Size -> Size #

sz :: Format r (Size -> r) #

`Format` a `Size` using a human readable representation

    >>> format sz 42
    "42 B"
    >>> format sz 2309
    "2.309 KB"
    >>> format sz 949203
    "949.203 KB"
    >>> format sz 1600000000
    "1.600 GB"
    >>> format sz 999999999999999999
    "999999.999 TB"

bytes :: Integral n => Size -> n #

Extract a size in bytes

kilobytes :: Integral n => Size -> n #

    1 kilobyte = 1000 bytes

megabytes :: Integral n => Size -> n #

    1 megabyte = 1000 kilobytes

gigabytes :: Integral n => Size -> n #

    1 gigabyte = 1000 megabytes

terabytes :: Integral n => Size -> n #

    1 terabyte = 1000 gigabytes

kibibytes :: Integral n => Size -> n #

    1 kibibyte = 1024 bytes

mebibytes :: Integral n => Size -> n #

    1 mebibyte = 1024 kibibytes

gibibytes :: Integral n => Size -> n #

    1 gibibyte = 1024 mebibytes

tebibytes :: Integral n => Size -> n #

    1 tebibyte = 1024 gibibytes

# File status

data FileStatus #

POSIX defines operations to get information, such as owner, permissions, size and access times, about a file. This information is represented by the `FileStatus` type.

Note: see `chmod`.

Limitations: Support for high resolution timestamps is filesystem dependent:

- HFS+ volumes on OS X only support whole-second times.

stat :: MonadIO io => FilePath -> io FileStatus #

Get the status of a file

lstat :: MonadIO io => FilePath -> io FileStatus #

Get the status of a file, but don't follow symbolic links

fileSize :: FileStatus -> Size #

Size of the file in bytes. Does not follow symlinks

accessTime :: FileStatus -> POSIXTime #

Time of last access

modificationTime :: FileStatus -> POSIXTime #

Time of last modification

statusChangeTime :: FileStatus -> POSIXTime #

Time of last status change (i.e. owner, group, link count, mode, etc.)

isBlockDevice :: FileStatus -> Bool #

Checks if this file is a block device.

isCharacterDevice :: FileStatus -> Bool #

Checks if this file is a character device.

isNamedPipe :: FileStatus -> Bool #

Checks if this file is a named pipe device.

isRegularFile :: FileStatus -> Bool #

Checks if this file is a regular file device.

isDirectory :: FileStatus -> Bool #

Checks if this file is a directory device.

isSymbolicLink :: FileStatus -> Bool #

Checks if this file is a symbolic link device.

isSocket :: FileStatus -> Bool #

Checks if this file is a socket device.

cmin :: MonadIO io => UTCTime -> FilePath -> io Bool #

Check if a file was last modified after a given timestamp

cmax :: MonadIO io => UTCTime -> FilePath -> io Bool #

Check if a file was last modified before a given timestamp

# Headers

data WithHeader a #

Constructors

Header a | The first line with the header
Row a a | Every other line: 1st element is header, 2nd element is original row

#### Instances

Instances details

Show a => Show (WithHeader a) # |
Instance details Defined in Turtle.Prelude Methods showsPrec :: Int -> WithHeader a -> ShowS # show :: WithHeader a -> String # showList :: [WithHeader a] -> ShowS #

header :: Shell a -> Shell (WithHeader a) #

# Exceptions

data ProcFailed #

Constructors

ProcFailed |
Fields procCommand :: Text procArguments :: [Text] procExitCode :: ExitCode

#### Instances

Instances details

Exception ProcFailed # |
Instance details Defined in Turtle.Prelude Methods toException :: ProcFailed -> SomeException # fromException :: SomeException -> Maybe ProcFailed # displayException :: ProcFailed -> String # backtraceDesired :: ProcFailed -> Bool #
Show ProcFailed # |
Instance details Defined in Turtle.Prelude Methods showsPrec :: Int -> ProcFailed -> ShowS # show :: ProcFailed -> String # showList :: [ProcFailed] -> ShowS #

data ShellFailed #

Constructors

ShellFailed |
Fields shellCommandLine :: Text shellExitCode :: ExitCode

#### Instances

Instances details

Exception ShellFailed # |
Instance details Defined in Turtle.Prelude Methods toException :: ShellFailed -> SomeException # fromException :: SomeException -> Maybe ShellFailed # displayException :: ShellFailed -> String # backtraceDesired :: ShellFailed -> Bool #
Show ShellFailed # |
Instance details Defined in Turtle.Prelude Methods showsPrec :: Int -> ShellFailed -> ShowS # show :: ShellFailed -> String # showList :: [ShellFailed] -> ShowS #