Live data from Hacker News

Use Haskell for shell scripting

haskellforall.com

71–80 of 105 posts

Re: Use Haskell for shell scripting

#71

Earlier quoted context omitted.

> If your arguments aren't exclusive, you can pass a list of algebraic data. Which you need to prefix to avoid clashes. > If they are exclusive, you can construct a type for them. Which is going to end up being a record, which: - is awkward to build (compared to just giving options to a command or arguments to a function) - will most likely need to be an instance of Default - which needs to have its fields prefixed t…

> prefixes, default instances Also bad setters ("record {field = val}" looks nice but useless, as not a function). I hope the developers of GHC also clearly see the problem and someday will be engaged in it. Then the language becomes much more expressive. Is that task exists somewhere in roadmap?

There have been probably 15 different proposals for this throughout the years. They never make enough momentum to go through. While record pain points seem like a huge deal, in practice they're not sufficiently bad to motivate changes in the language in the face of the various tradeoffs that would have to be made.

Today, typeclasses and lenses cover 99% of "the record problem" as far as I've experienced.

Re: Use Haskell for shell scripting

#72
post #40
post #25

OK. How do you easily fork to run a command in the background? How does setting up pipes work? What's the idiom for chdir'ing to a subdirectory such that you pop back out again when you're done (I'd use a subshell with (ch xxx; ...) in bash)? Getting into more tricky stuff, what's the equivalent of This doesn't really demonstrate anything that shell scripts are actually written for: orchestrating and composing other…

Did we read the same article? The entire 'streaming section' is about pipes and I/O redirects. Running a command in the background is just forkIO $ proc ..etc.., as in regular Haskell. Nothing tricky about it.

The streaming section of the article has nothing about composing processes, that I could see; it appeared to be about treating the output of commands as input to Haskell lazy lists. I may have misread it, though.

Here's a pattern that comes up fairly frequently for me:

  foo | fgrep -v -f 
It uses the second column in info.csv as fixed strings to match inside lines in the output of foo, and filters them out, with the remaining lines going to bar.

All 4 processes (foo, bar, fgrep, cut) run concurrently. Likely fgrep will block on cut sooner or later, but the point is that multiple communicating concurrent processes are set up using a fairly easy to use DSL.

That's what a shell is, to me.

Re: Use Haskell for shell scripting

#73
Please forgive my lack of familiarity with the concurrent workings of Haskell, but since the Shell streams are based off []/IO, and not Concurrent.Chan, does this mean one turtle function has to complete (and write its results to memory) before the next turtle function can run?

To me, magic bits of shell scripts which turtle would need to improve upon were it to replace said scripts are not the loop constructs, conditionals, or even the type system (even though it's completely lacking in bash), it is the ability to use pipes to link processes concurrently.

Re: Use Haskell for shell scripting

#74
post #58

Earlier quoted context omitted.

I do a lot of shell scripting, and I'm not sure there is such a thing as a "proper" shell script. The shell just isn't a great programming language. Just about any modern scripting language is better, starting with Perl. But the shell has been the lingua franca of the Unix world for decades now. It's the one language that you can pretty much guarantee is on any Unix or Linux server, even pretty ancient ones. I don't…

> you can pretty much guarantee is on any Unix or Linux server, even pretty ancient ones Well, yes and no. You can get reasonable compatibility with different Unix flavours if you stick to sh. Your script is not going to work on BSDs once you start using bash specific features, though. Fun fact: on FreeBSD bash does not live in /bin/bash, it's in /usr/local/bin/bash. Every time you write a shebang with /bin/bash hard…

Oh that's interesting. I'd assumed that FreeBSD had made bash the default shell around the same time that Mac OS did. I guess my point still stands for /bin/sh. Not a fun programming language though.

Re: Use Haskell for shell scripting

#75
post #9

Thanks Gabriel Gonzalez! There is a comment on the blog post (by Chris Done) asking how it deals with piping. I really wonder about that too. Some related projects: - Joey Hess recently released a nice Haskell-to-sh compiler. I like this approach as the resulting sh scripts are runnable on pretty much every *nix. https://joeyh.name/blog/entry/shell_monad/ - Chris Done also released a lib to do shell stuff from Haskel…

You use `inproc` and `inshell` for piping. For example, here's the type of `inshell`: inshell :: Text -- Shell command -> Shell Text -- Standard input to feed command -> Shell Text -- Standard output produced by command I made one intentional simplification in the API, which was to not provide a way to capture standard error. It's definitely possible to provide such a utility, but I wanted to simplify things as much…

Thanks for this elaborate response.

Re: Use Haskell for shell scripting

#76
post #25

OK. How do you easily fork to run a command in the background? How does setting up pipes work? What's the idiom for chdir'ing to a subdirectory such that you pop back out again when you're done (I'd use a subshell with (ch xxx; ...) in bash)? Getting into more tricky stuff, what's the equivalent of This doesn't really demonstrate anything that shell scripts are actually written for: orchestrating and composing other…

> How do you easily fork to run a command in the background? `turtle` provides `fork` for running a command in the background. Example usage: example = do using (fork commandToForkInAnotherThread) theseCommandsStillRunInTheOriginalThread > How does setting up pipes work? See the `inproc` and `inshell` commands, which let you convert any shell command into a stream transformation embedded within Haskell. > What's the…

FWIW:

>(foo) does the same thing, except the other way around, for process output.

Re: Use Haskell for shell scripting

#77
post #9

Thanks Gabriel Gonzalez! There is a comment on the blog post (by Chris Done) asking how it deals with piping. I really wonder about that too. Some related projects: - Joey Hess recently released a nice Haskell-to-sh compiler. I like this approach as the resulting sh scripts are runnable on pretty much every *nix. https://joeyh.name/blog/entry/shell_monad/ - Chris Done also released a lib to do shell stuff from Haskel…

You use `inproc` and `inshell` for piping. For example, here's the type of `inshell`: inshell :: Text -- Shell command -> Shell Text -- Standard input to feed command -> Shell Text -- Standard output produced by command I made one intentional simplification in the API, which was to not provide a way to capture standard error. It's definitely possible to provide such a utility, but I wanted to simplify things as much…

"process-streaming" is more like a set of helper functions for "process"; it doesn't provide formatting, regexps, or OS-independent implementations of typical shell commands. It does support piping of processes, though.

Re: Use Haskell for shell scripting

#79

Earlier quoted context omitted.

> If your arguments aren't exclusive, you can pass a list of algebraic data. Which you need to prefix to avoid clashes. > If they are exclusive, you can construct a type for them. Which is going to end up being a record, which: - is awkward to build (compared to just giving options to a command or arguments to a function) - will most likely need to be an instance of Default - which needs to have its fields prefixed t…

Prefixes are a problem, no arguing about that. But... > is awkward to build (compared to just giving options to a command or arguments to a function) Idiomatic bash: apt-get install package_name Idiomátic haskell: apt_get $ AptInstall package_name What is so awkward about that?

First, it doesn't let you install multiple packages in one go (or let you install a specific package version). Secondly, it doesn't support apt-get options like -m, -d -n...

You could extend your argument structure for this, but then you need to specify every argument all the time, or have the user modify a default value. This is definitely awkward compared to straight shell.

Re: Use Haskell for shell scripting

#80
post #59

Earlier quoted context omitted.

Take lstree then. How would you give it an option giving the kind of ordering you want?

I guess you wouldn't, you'd have a sort function afterwards. ...for Unix' insistence on composability, the shell tools are often unnecessarily monolithic, probably because that's the only sane way if the only type you have in interconnect is `string`.

Sure, but consider the common case of wanting the most recent file/directory in a directory. This would be something like "ls -t|head -n 1". It's pretty convenient, AND your ls function still returns only file and directory names, no additional information.

Here, you'd need to either parametrize the return type of ls to get simple strings (which is what you want most of time) or additional metadata, or alternatively to have different ls commands.

Post reply on HN