Proposal: Add showCommandForUser to process:System.Process

Add showCommandForUser to process:System.Process http://hackage.haskell.org/trac/ghc/ticket/4305 There are many programs (e.g. ghc and Cabal) which run other programs, and when run with -v want to show the user what they are running. The user then often wants to run the command by hand, in order to debug a problem, but this can be tricky when the command or its arguments include spaces or other characters treated specially by shells. This proposal is for a System.Process.showCommandForUser function in the process package, such that showCommandForUser cmd args can be copied and pasted directly into a shell. I would have put this in System.Cmd, except that module is earmarked to be deprecated. The code already existed within System.Process; I've just rearranged it a bit: showCommandForUser :: FilePath -> [String] -> String showCommandForUser cmd args = unwords (map translate (cmd : args)) translate :: String -> String #if mingw32_HOST_OS translate str = '"' : snd (foldr escape (True,"\"") str) where escape '"' (b, str) = (True, '\\' : '"' : str) escape '\\' (True, str) = (True, '\\' : '\\' : str) escape '\\' (False, str) = (False, '\\' : str) escape c (b, str) = (False, c : str) #else translate str = '\'' : foldr escape "'" str where escape '\'' = showString "'\\''" escape c = showChar c #endif The fallback for rawSystem is now rawSystem cmd args = system (showCommandForUser cmd args) except with hugs on Windows, where for some reason it's rawSystem cmd args = system (cmd ++ showCommandForUser "" args) which is surely wrong, but how it behaved before. Discussion period: 2 weeks, until 26 Sep 2010. Thanks Ian

On 12 September 2010 21:24, Ian Lynagh
Add showCommandForUser to process:System.Process http://hackage.haskell.org/trac/ghc/ticket/4305
There are many programs (e.g. ghc and Cabal) which run other programs, and when run with -v want to show the user what they are running. The user then often wants to run the command by hand, in order to debug a problem, but this can be tricky when the command or its arguments include spaces or other characters treated specially by shells.
+1 I think this is an important use-case, and the need for cross-platform support justifies having it in the library. A related use-case which would also use this function is a --dry-run option that just prints out the command without running it (like "make -n", "darcs send --dry-run" etc.) which is useful for, um, non-destructive debugging. Conrad.
This proposal is for a System.Process.showCommandForUser function in the process package, such that showCommandForUser cmd args can be copied and pasted directly into a shell.
I would have put this in System.Cmd, except that module is earmarked to be deprecated.
The code already existed within System.Process; I've just rearranged it a bit:
showCommandForUser :: FilePath -> [String] -> String showCommandForUser cmd args = unwords (map translate (cmd : args))
translate :: String -> String #if mingw32_HOST_OS translate str = '"' : snd (foldr escape (True,"\"") str) where escape '"' (b, str) = (True, '\\' : '"' : str) escape '\\' (True, str) = (True, '\\' : '\\' : str) escape '\\' (False, str) = (False, '\\' : str) escape c (b, str) = (False, c : str) #else translate str = '\'' : foldr escape "'" str where escape '\'' = showString "'\\''" escape c = showChar c #endif
The fallback for rawSystem is now
rawSystem cmd args = system (showCommandForUser cmd args)
except with hugs on Windows, where for some reason it's
rawSystem cmd args = system (cmd ++ showCommandForUser "" args)
which is surely wrong, but how it behaved before.
Discussion period: 2 weeks, until 26 Sep 2010.
Thanks Ian
_______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries

On 09/12/10 08:24, Ian Lynagh wrote:
Add showCommandForUser to process:System.Process http://hackage.haskell.org/trac/ghc/ticket/4305
There are many programs (e.g. ghc and Cabal) which run other programs, and when run with -v want to show the user what they are running. The user then often wants to run the command by hand, in order to debug a problem, but this can be tricky when the command or its arguments include spaces or other characters treated specially by shells.
*Which* shells, though, can it run in? My particular example is I use "fish" shell on Linux, which has similar but not identical quoting-and-special-character rules to Bash. The convention in the Linux/Unix world these days, I believe (on the internet and otherwise) is to post commands in a format that works in Bash / POSIX sh / whatever works in most/all default Unix shells that currently exist. It looks like the patch's method of single-quoting everything and adding the usual trick to quote single-quotes ( '\'' ) should work fine for shell compatibility as well as user-readability. (Ignoring Windows conventions I'm not familiar with.) ( Csh/Tcsh looks somewhat hopeless to add compatibility with: e.g. even in single-quotes in scripts, '!' needs to be backslash-escaped*. Switching to using backslashes for everything instead of single-quotes would be way too ugly. * http://www.mpi-inf.mpg.de/~uwe/lehre/unixffb/quoting-guide.html#para:csh-tcs... ) ...So, at least from the Linux side of things, +1. -Isaac

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On 9/12/10 21:58 , Isaac Dupree wrote:
I'm not familiar with.) ( Csh/Tcsh looks somewhat hopeless to add compatibility with: e.g. even in single-quotes in scripts, '!' needs to be backslash-escaped*. Switching to using backslashes for everything instead of single-quotes would be way too ugly.
Generally, the rule is to assume the original Bourne shell as a baseline; csh/tcsh users can fend for themselves, as the heyday of the CSRG is long past :) - -- brandon s. allbery [linux,solaris,freebsd,perl] allbery@kf8nh.com system administrator [openafs,heimdal,too many hats] allbery@ece.cmu.edu electrical and computer engineering, carnegie mellon university KF8NH -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.10 (Darwin) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/ iEYEARECAAYFAkyNhssACgkQIn7hlCsL25X9kQCeMaRlYkiD4xqrux3s+MVlXSac 9ecAn0ZElyHIGAcRWiPVO7HNA90H+nY/ =sUcq -----END PGP SIGNATURE-----

On Sun, Sep 12, 2010 at 09:58:44PM -0400, Isaac Dupree wrote:
On 09/12/10 08:24, Ian Lynagh wrote:
Add showCommandForUser to process:System.Process http://hackage.haskell.org/trac/ghc/ticket/4305
There are many programs (e.g. ghc and Cabal) which run other programs, and when run with -v want to show the user what they are running. The user then often wants to run the command by hand, in order to debug a problem, but this can be tricky when the command or its arguments include spaces or other characters treated specially by shells.
*Which* shells, though, can it run in?
Ah, you are right, I should have added a haddock doc! -- | Given a program @p@ and arguments @args@, -- @showCommandForUser p args@ returns a string suitable for pasting -- into sh (on POSIX OSs) or cmd.exe (on Windows). Thanks Ian

+1 for the general principal. I'm a little ambivalent about changing quoting rules depending on the operating system: the operating system does not necessitate a particular shell. A more general API might be to support a variety of quoting styles, but that might be a smidge overkill. Cheers, Edward Excerpts from Ian Lynagh's message of Sun Sep 12 08:24:24 -0400 2010:
Add showCommandForUser to process:System.Process http://hackage.haskell.org/trac/ghc/ticket/4305
There are many programs (e.g. ghc and Cabal) which run other programs, and when run with -v want to show the user what they are running. The user then often wants to run the command by hand, in order to debug a problem, but this can be tricky when the command or its arguments include spaces or other characters treated specially by shells.
This proposal is for a System.Process.showCommandForUser function in the process package, such that showCommandForUser cmd args can be copied and pasted directly into a shell.
I would have put this in System.Cmd, except that module is earmarked to be deprecated.
The code already existed within System.Process; I've just rearranged it a bit:
showCommandForUser :: FilePath -> [String] -> String showCommandForUser cmd args = unwords (map translate (cmd : args))
translate :: String -> String #if mingw32_HOST_OS translate str = '"' : snd (foldr escape (True,"\"") str) where escape '"' (b, str) = (True, '\\' : '"' : str) escape '\\' (True, str) = (True, '\\' : '\\' : str) escape '\\' (False, str) = (False, '\\' : str) escape c (b, str) = (False, c : str) #else translate str = '\'' : foldr escape "'" str where escape '\'' = showString "'\\''" escape c = showChar c #endif
The fallback for rawSystem is now
rawSystem cmd args = system (showCommandForUser cmd args)
except with hugs on Windows, where for some reason it's
rawSystem cmd args = system (cmd ++ showCommandForUser "" args)
which is surely wrong, but how it behaved before.
Discussion period: 2 weeks, until 26 Sep 2010.
Thanks Ian

On 15/09/2010 03:45, Edward Z. Yang wrote:
+1 for the general principal.
I'm a little ambivalent about changing quoting rules depending on the operating system: the operating system does not necessitate a particular shell. A more general API might be to support a variety of quoting styles, but that might be a smidge overkill.
The System.Cmd API is already OS-dependent in this sense: System.Cmd.system passes the string to /bin/sh on POSIX and cmd.exe on Windows, so Ian's proposal is consistent with that behaviour. Cheers, Simon

Excerpts from Simon Marlow's message of Wed Sep 15 10:53:11 -0400 2010:
The System.Cmd API is already OS-dependent in this sense: System.Cmd.system passes the string to /bin/sh on POSIX and cmd.exe on Windows, so Ian's proposal is consistent with that behaviour.
Ah, that's right. Basing this function on the behavior of system() seems like the right thing to do. Edward
participants (6)
-
Brandon S Allbery KF8NH
-
Conrad Parker
-
Edward Z. Yang
-
Ian Lynagh
-
Isaac Dupree
-
Simon Marlow