hsshellscript-3.1.0: src/HsShellScript/Shell.hs
-- #hide
module HsShellScript.Shell where
import Data.List
-- import System
-- |
-- Generate command (for a shell) which corresponds to the specified program
-- name and argument list. The program name and arguments are the usual
-- parameters for calling an external program, like when using
-- @runProcess@ or @run@. The generated shell command
-- would achieve the same effect. The name and the arguments are properly
-- quoted, using 'shell_quote'.
--
-- Note: The quoted strings are correctly recognized in shell scripts. But the shell bash has an annoying history expansion \"feature\", which causes
-- it to choke on exclamation marks, when in interactive mode, even when quoted with double quotes. You can turn it off with @set +o histexpand@.
shell_command :: String -- ^ name or path of the executable
-> [String] -- ^ command line arguments
-> String -- ^ shell command
shell_command k par =
concat (intersperse " " (map shell_quote (k:par)))
-- |
-- Quote shell metacharacters.
--
-- This function quotes strings, such that they are not misinterpreted by
-- the shell. It tries to be friendly to a human reader - when special
-- characters are present, then the string is quoted with double quotes. If
-- not, it is left unchanged.
--
-- The list of exacly which characters need to be quoted has been taken
-- from the bash source code. Bash in turn, implements POSIX 1003.2. So the
-- result produced should be correct. From the bash info pages:
-- \"... the rules for evaluation and quoting are taken from the POSIX
-- 1003.2 specification for the `standard' Unix shell.\"
--
-- Note: The quoted strings are correctly recognized in shell scripts. But the shell bash has an annoying history expansion \"feature\", which causes
-- it to choke on exclamation marks, when in interactive mode, even when quoted with double quotes. You can turn it off with @set +o histexpand@.
--
-- See 'quote'.
shell_quote :: String -> String
shell_quote "" = "\"\""
shell_quote txt =
let need_to_quote c = c `elem` "' \t\n\"\\|&;()<>!{}*[?]^$`#"
in if any need_to_quote txt
then '"' : quote0' txt
else txt
where
quote0' :: String -> String
quote0' (z:zs) =
if (z `elem` "\"$`\\") then ('\\':(z:(quote0' zs)))
else (z:(quote0' zs))
quote0' "" = "\""
-- |
-- Quote special characters inside a string for the shell
--
-- This quotes special characters inside a string, such that it is
-- recognized as one string by the shell when enclosed in double quotes.
-- Doesn't add the double quotes.
--
-- Note: The quoted strings are correctly recognized in shell scripts. But the shell bash has an annoying history expansion \"feature\", which causes
-- it to choke on exclamation marks, when in interactive mode, even when quoted with double quotes. You can turn it off with @set +o histexpand@.
--
-- See 'quote', 'shell_quote'.
quote0 :: String -> String
quote0 (z:zs) =
if (z `elem` "\"$`\\") then ('\\':(z:(quote0 zs)))
else (z:(quote0 zs))
quote0 "" = ""
-- |
-- Quote a string for the shell
--
-- This encloses a string in double quotes and quotes any special
-- characters inside, such that it will be recognized as one string by a
-- shell. The double quotes are added even when they aren't needed for this
-- purpose.
--
-- Note: The quoted strings are correctly recognized in shell scripts. But the shell bash has an annoying history expansion \"feature\", which causes
-- it to choke on exclamation marks, when in interactive mode, even when quoted with double quotes. You can turn it off with @set +o histexpand@.
--
-- See 'quote0', 'shell_quote'.
quote :: String -> String
quote str = "\"" ++ quote0 str ++ "\""