4 ms·
Speak for yourself, and I don't know anyone that puts the input redirection first. I do this: (xargs foo | grep bar | sort | wc -l) < file It makes the pipe
by blasdel 17y ago
Speak for yourself, and I don't know anyone that puts the input redirection first. I do this:
(xargs foo | grep bar | sort | wc -l) < file
It makes the pipeline one command, both lexically (verb comes first) and concretely (the pipeline is kicked off in a subshell)
- barrkel 17y agoAt the expense of the data flowing from right to left to right, from the outside in. At least with cat, data flows unambiguously from left to right.
- blasdel 17y agoBut using cat totally fucks up the calling conventions: it puts the operand as the second of many arguments. Which one of these doesn't belong?: verb file cat file | verb1 | verb2 | verb3 (verb1 | verb2 | verb3) < file verb123 file EDIT: Consider the calling conventions, which one of these handles it's arguments differently? Assume that verb123 is an equivalent to the pipeline -- the subshell+stdin construction lends itself to shell aliases: alias verb123="(verb1 | verb2 | verb3) < "
- barrkel 17y agoI have no idea which one doesn't belong. Is 'verb123' the moral equivalent of '(verb1 | verb2 | verb3)'? In that case, it's the first one. But that's visible from the first word on the line, so I'm still not getting the picture. Of course, with the usual argument vs stdin conventions, either of the middle two could also be rewritten: verb1 file | verb2 | verb3 This is probably how I'd write such a chain.
- pyre 17y agoBut does the time it takes to launch the subshell equal the amount of time it takes to launch cat? If so your improvement is a NOOP.
- blasdel 17y agofork + 3x(fork+exec) is going to be cheaper than 4x(fork+exec), especially if cat isn't resident. The point is a logical improvement anyway (not burying the input argument near the beginning). I'm kind of surprised that the bash folks haven't turned cat into a builtin like they did with time and some of the other coreutils. It's too bad it's about 30 years too late to stem the tide of shit like cat -v: http://harmful.cat-v.org/cat-v/ http://harmful.cat-v.org/cat-v/
- pyre 17y agoBy the reasoning in your link, your suggestion of bash making 'cat' one of the built-in commands is the "cancer that's bloating UNIX."
- blasdel 17y agoThe shell has always been the kitchen sink full of glue holding the whole thing together. There have always been builtins: language control structures, job control, etc. -- there are some things you can't trust others not to fuck up, and where the coupling would just get ridiculous. Here's cat as a pure sh builtin: shcat { for arg in "$@"; do exec 3<>"$arg" while read line <&3; do echo "$line" done exec 3>&- done } The shell by it's very nature can't just do exactly one task well, it's a programmable environment for living in. The cancer that's bloating UNIX was the way that the BSD and especially the GNU crews took simple tools and cross-pollinated them randomly with stupid shit. Try running "/bin/true --help" on a GNU system sometime -- there's a damn good reason why "your shell may have its own version of true".
- pyre 17y ago% /bin/true --help Usage: /bin/true [ignored command line arguments] or: /bin/true OPTION Exit with a status code indicating success. --help display this help and exit --version output version information and exit NOTE: your shell may have its own version of true, which usually supersedes the version described here. Please refer to your shell's documentation for details about the options it supports. Report bugs to <bug-coreutils@gnu.org>. I wouldn't necessarily call that 'bloated' unless you feel that any program that uses one bit more than absolutely necessary should be scrapped as 'bloated beyond belief.' > there's a damn good reason why "your shell may have its own version of true". Because why exactly?
- rlpb 17y agoFor ad-hoc stuff, I tend to do different things depending on where my cursor is and how I built up to a complex pipeline.
- jrockway 17y agoSpoken like a Haskell programmer, who might write: (wc Lines) . sort . (grep "bar") . (xargs "foo") =<< file But note in this case that all the data "flows in the same direction".
- blasdel 17y agohas been a Haskell programmer since 2005, before the dawn of dons wc Lines $ sort $ grep "bar" $ xargs "foo" =<< file
- jrockway 17y agoThat does not parse the way you think it does; the fixity of =<< is greater than $. You would need the shell-style parens if you insist on application instead of composition :) Prelude> :info $ ($) :: (a -> b) -> a -> b -- Defined in GHC.Base infixr 0 $ Prelude> :info =<< (=<<) :: (Monad m) => (a -> m b) -> m a -> m b -- Defined in Control.Monad infixr 1 =<< Prelude> :info . (.) :: (b -> c) -> (a -> b) -> a -> c -- Defined in GHC.Base infixr 9 . Incidentally, the parens in my example are actually unnecessary. Function application is about 10, and (.) is 9.
- gnosis 17y agoI almost never use < It's too easy to make a mistake and type > ..and that can ruin your whole day.
- blasdel 17y agoI have fucked myself more than once by typing > instead of >> I find that to be a far more pernicious design error -- they should have made the longer token the destructive one, or used another character in it.
- thornist 17y agozsh with 'setopt noclobber' won't overwrite an existing file with '>', instead requiring '>|'. The history recall conveniently fills in the '|' for you if you up-arrow after a failed call. It works pretty nicely - I imagine other shells have similar.
- wendroid 17y agoYou get mostly both with xargs foo < file | grep bar | sort | wc -l