[HN Gopher] Useful Uses of Cat
       ___________________________________________________________________
        
       Useful Uses of Cat
        
       Author : todsacerdoti
       Score  : 144 points
       Date   : 2024-02-21 18:53 UTC (4 hours ago)
        
 (HTM) web link (two-wrongs.com)
 (TXT) w3m dump (two-wrongs.com)
        
       | gruturo wrote:
       | The concept presented is something I can agree with in principle,
       | but "transforming a filename into the content of the file" is a
       | really thin justification for a responsibility.
       | 
       | By all means don't build something where you have cascading
       | effect and need to retest an entire pipeline, but this is _not_
       | it.
       | 
       | P.S.
       | 
       | And if you really really want to keep it separate, just do "<
       | access.log head -500 etc etc etc" (no I didn't forget a pipe. And
       | yes the "< inputfile" works even if it's in front of what you're
       | calling).
        
         | hk__2 wrote:
         | > And if you really really want to keep it separate, just do "<
         | access.log head -500 etc etc etc" (no I didn't forget a pipe.
         | And yes the "< inputfile" works even if it's in front of what
         | you're calling).
         | 
         | Or just use `cat` and let the pipe separate the different
         | steps. "< access.log head" is nice but it breaks this
         | representation where each step is piped into the next one.
         | Sure, once you're done fiddling you can rewrite the thing to
         | remove the "cat", but when you are constructing the thing I
         | find it clearer to use cat.
        
           | stouset wrote:
           | > Sure, once you're done fiddling you can rewrite the thing
           | to remove the "cat"
           | 
           | Or just... don't?
        
             | margalabargala wrote:
             | Sure. Don't. Or do. Whatever you prefer.
        
           | kristjansson wrote:
           | > it breaks this representation where each step is piped into
           | the next one
           | 
           | No it doesn't?                 < access.log head -n 500 |
           | grep mail | perl -e ...
           | 
           | is completely valid, and reads right-to-left as well as the
           | cat version. IMO using stdin is preferable to either solution
           | in TFA.
        
             | ufo wrote:
             | This works but it's so ugly :(
        
               | kristjansson wrote:
               | I think it's beautiful? Reads left-to-right, has nice
               | symmetry if you pipe to an output file like:
               | < infile some_cmd > outfile
               | 
               | and real clarifies what's a shell command, what's a
               | redirection, etc.
        
             | n_plus_1_acc wrote:
             | I agree that it's more elegant, but it requires you to
             | remember the operator precendence of < vs |
        
               | kristjansson wrote:
               | It's not really a precedence relation as much as it's
               | part of shell syntax. There are separators[0], and
               | anything sequence of tokens between a separator is a
               | command[1]. A command decomposes further, of course, but
               | the only thing the programmer needs to know here is that
               | separators are a different kind of thing than commands.
               | 
               | [0]: newline, '||', '&&', '&', ';', ';;', ';&', ';;&',
               | '|', '|&', '(', or ')'.
               | 
               | [1]: https://www.gnu.org/software/bash/manual/bash.html#S
               | imple-Co...
        
         | TOGoS wrote:
         | > _transforming a filename into the content of the file " is a
         | really thin justification for a responsibility_
         | 
         | This is one of those things where I think it is until it isn't.
         | 
         | I sometimes second-guess myself when I think I might be over-
         | single-responsibilifying. "Well in practice these two things
         | are so trivial that this feels a little silly."
         | 
         | It often turns out to have been a good call in hindsight,
         | especially when working with other people who aren't
         | necessarily thinking about these things at all. If the
         | responsibilities have been sufficiently split up, they're more
         | likely to change only the part that needed to be changed, and
         | less likely to complectify the two things together that really
         | shouldn't've been. Or when I go "oh wow that thing that I
         | thought I overly-abstracted sure composes well with this
         | unexpected new thing!"
         | 
         | Hardcore separation of concerns is just another method of
         | defensive programming.
         | 
         | > _< access.log head -500 etc etc etc_
         | 
         | It's too bad that the syntax is so different. Why does the
         | first stage not end with "|"? There's space for shell syntax
         | improvements, here. Maybe a 'cat'-like builtin that translates
         | `cat foo | bar` into `bar <foo` so you can have the nice syntax
         | but don't needlessly create processes would leave everyone
         | happy.
        
         | ajross wrote:
         | > "transforming a filename into the content of the file" is a
         | really thin justification for a responsibility.
         | 
         | Uh... I dunno, but my lizard brain thinks that the whole idea
         | of mediating filesystem operations on storage and IPC
         | mechanisms like pipes is a lot _more_ complicated, magic, and
         | deserving of a single command than merely filtering the data on
         | stdin.
         | 
         | I agree with the article and the logic, and think this historic
         | meme was basically wrong originally. You string up your chain
         | of pipelines with the first element being "where does it come
         | from?" and not merely whatever the first operation happens to
         | be just because that operation allows for some kind of file
         | input or redirection syntactically.
        
         | jiveturkey wrote:
         | in the example given in the website, it could all be done in
         | the perl! no need for the pipeline at all.
        
       | svilen_dobrev wrote:
       | well, whole thing can be written in the perl -ne ...
       | 
       | but that absolutely kills modularity / composability
       | 
       | so yes, "cat xyz" plays a source - and can be replaced with
       | another source - without touching all other stuff.
        
         | hk__2 wrote:
         | > so yes, "cat xyz" plays a source - and can be replaced with
         | another source - without touching all other stuff.
         | 
         | This. I often have to read logs and being able to apply the
         | same oneliner on older logs just by adding a "z" in front of
         | "cat" to read .log.gz instead of .log files is extremely
         | useful.
        
           | kqr wrote:
           | Good point! I often experiment with cat response.json and
           | then replace cat with curl once I'm happy.
        
       | lenerdenator wrote:
       | came looking for feline-related content. left disappointed.
        
         | lonlazarus wrote:
         | Try tumblr
        
           | whatsinaname123 wrote:
           | Or reddit
        
         | p1mrx wrote:
         | Useful uses of cat:
         | 
         | - pest control
         | 
         | - entertainment
         | 
         | - transporting small solar arrays
        
           | omoikane wrote:
           | > transporting small solar arrays
           | 
           | I definitely need to hear more about this one.
        
             | lenerdenator wrote:
             | solar panel need sun.
             | 
             | cat like sleeping in sun.
             | 
             | attach solar panel to cat.
             | 
             | cat occasionally moves to remain in sun as it naps.
        
           | klyrs wrote:
           | My cat recently discovered that her fur can absorb a toilet
           | bowl full of water. This seems like it could be useful, if
           | you need a very wet floor immediately.
        
         | brightsize wrote:
         | Here you go. This is the second time in the past few years that
         | cat was used to process bikers in the NW WA wilderness. The
         | first time was fatal. I used to live about 15min from where
         | this incident occurred. https://www.seattletimes.com/seattle-
         | news/cougar-attacks-cyc...
        
         | xanderlewis wrote:
         | Those looking for useful uses of the category of (locally
         | small) categories will similarly be disappointed.
        
         | grork wrote:
         | Especially since the versatility of A Cat is unbounded.
        
         | slingnow wrote:
         | I'm sure this generic "joke" would be a real gut buster over on
         | Reddit.
        
           | lenerdenator wrote:
           | As a cat servant I care not about gut-busting.
        
         | Findecanor wrote:
         | And here I had been hoping on tips and tricks for printing the
         | file catalog on TRSDOS, Flex, Sinclair or RISC OS.
        
         | glxxyz wrote:
         | I was half-expecting it to be about this strange book:
         | https://en.wikipedia.org/wiki/101_Uses_for_a_Dead_Cat
        
       | kkfx wrote:
       | an useful use, back in time, was to assemble partial ISO file of
       | OpenSolaris SXDE, the first open version before Ian
       | Murdock/OpenIndiana. It's more an anecdote but considering the
       | usefulness of netcat in many cases such "cat binary use" might
       | still be relevant in some embedded scenarios.
        
       | gregfjohnson wrote:
       | Thoughtful article - thanks. Humorous aside: I recently came
       | across a hilariously named, occasionally useful, related utility:
       | "tac".
        
         | ryukoposting wrote:
         | It ships with coreutils! `rev` is another one in a similar
         | vein, though that's not coreutils.
        
       | hiAndrewQuinn wrote:
       | `cat x | Y | Z` is Subject-Verb-Object.
       | 
       | `Y x | Z` is Verb-Subject-Object.
       | 
       | That's why I prefer using cat "uselessly".
        
         | kazinator wrote:
         | < x Y | Z > w
         | 
         | Y takes input redirected from x, piped into Z, which outputs
         | into w.
        
           | TeMPOraL wrote:
           | > _Y takes input redirected from x, piped into Z, which
           | outputs into w._
           | 
           | I.e.                 x | Z | tee w | Y
           | 
           | ? that's... something else entirely.
        
             | _kst_ wrote:
             | No, the command is                   < x Y | Z > w
             | 
             | where x and w are files, not commands.
             | 
             | Something that "cat file | ..." advocates might be
             | overlooking is that a redirection ("<inputfile",
             | ">outputfile", "2>errorfile") can appear anywhere within a
             | simple command, so these:                   command -option
             | < file         < file command -option         command <
             | file -option
             | 
             | are all exactly the same -- and of course very similar to
             | cat file | command -option
             | 
             | If the purpose of typing "cat file | command" is to put the
             | input file at the beginning (which does make logical
             | sense), you can achieve the same thing with "< file
             | command". Admittedly, it does look at bit strange if you're
             | not accustomed to it. (It even works with csh and tcsh.)
        
         | neuromanser wrote:
         | cat is a verb though
        
         | pwdisswordfishc wrote:
         | "x" is not a subject.
        
       | kazinator wrote:
       | This blogger does not seem to know that in the POSIX shell
       | syntax, redirections can be specified anywhere in the command:
       | < access.log head -n 500 | grep mail | perl -e
       | 
       | Now you can delete "head -n 500 |".
       | 
       | > _If we then delete only the head processing step we're left
       | without a step that transforms the string access.log into the
       | contents of the access log._
       | 
       | By introducing "cat access.log" we have the same problem: if we
       | delete only the cat processing step, we're left without a step
       | that transforms the string access.log into the contents. For the
       | useless cat to have the nice property that you can cleanly delete
       | it from the command line, you need:                  < access.log
       | | cat | head -n 500 ...
       | 
       | :)
        
       | jxy wrote:
       | I'm in the camp of using                   <input X|Y|Z >output
       | 
       | The point of this syntax is that I can readily replace it with
       | F() { X|Y|Z }         <input F >output
        
         | iforgotpassword wrote:
         | Since I like spaces around stuff I started putting two spaces
         | after the infile at some point.                 < infile  x | y
         | | z > outfile
         | 
         | I just didn't like how the filename was so close to the command
         | name ;)
        
         | CBLT wrote:
         | I'm in this camp as well, starting with input file redirection
         | just makes so much sense to me.
         | </proc/0/environ xargs -0
         | 
         | I also don't tend to want enormous volumes of text in my
         | terminal scrollback so I generally view files or pipe verbose
         | commands to `less`, then when I find what I want to send to the
         | terminal I use the `|` less command to pipe it to `cat`.
         | 
         | Or to grab just a few lines for my later reference:
         | kubectl get po/my-pod -o yaml | less         /* find the lines
         | I'm interest in */         -N         |^sed -n 34,35p
        
       | TehShrike wrote:
       | Typo in the title - should be "cat" not "Cat" (same as the h1 in
       | the linked article)
        
       | ufo wrote:
       | If the shell were to treat cat as a builtin, could it implement
       | cat| as a stdin redirect?
       | 
       | I wish I could write "useless cat" without people pestering me
       | about it.
        
         | kazinator wrote:
         | Bash allows the $(< file) syntax instead of $(cat file), and I
         | think the latter might be converted to the former.
        
           | neuromanser wrote:
           | It's built-in in Zsh: The substitution '$(cat foo)' may be
           | replaced by the faster '$(<foo)'.
           | 
           | https://zsh.sourceforge.io/Doc/Release/Expansion.html#Comman.
           | ..
        
       | NelsonMinar wrote:
       | Another reason to do `cat | foo` is because you can then quickly
       | change it to `zcat | foo` or some other source for the data by
       | editing the very beginning of the command.
        
         | pimlottc wrote:
         | less is useful for this if you have the lesspipe [0]
         | preprocessor installed
         | 
         | 0: https://github.com/wofr06/lesspipe
        
       | avgcorrection wrote:
       | Most immediate use: I have to google less shell syntax.
        
       | bee_rider wrote:
       | The reason these sequences of commands always start with cat, for
       | me at least, is that I just cat'd the file only to find it was
       | too long or noisy.                   cat filename.txt
       | Up | grep "thing I want"
       | 
       | Is fewer keystrokes than                   cat filename.txt
       | grep "thing I want" filename.txt
       | 
       | Or more likely                   cat filename.txt
       | grep filename.txt "thing I want"               grep "thing I
       | want" filename.txt
        
         | hnlmorg wrote:
         | You can also do:                   grep "thing I want" !$
         | 
         | Bash (and similar) will replace !$ with the last parameter of
         | the previous command.
         | 
         | This is a trick I've used lots when wanting to perform a non-
         | piping operation on a command I've 'cat'ed (eg 'rm -v !$')
         | 
         | I'd never criticise anyone for "useless" use of 'cat' though.
         | If the fork() overhead was really that critical then it
         | wouldn't be a shell command to begin with.
        
           | mmh0000 wrote:
           | Even easier, press alt+. (fewer keystrokes too! cli golf is
           | fun), it'll copy-and-paste the last parameter from the
           | previous command. If you press . multiple times it'll go
           | further back into your history.
        
           | bumblebeast wrote:
           | I just use <esc>. On the command line to bring back the last
           | argument.
           | 
           | Then I can look at it before hitting return
        
             | harrisi wrote:
             | shopt -s histverify
        
         | sophacles wrote:
         | I look through a lot of logs, so I've aliased `not` to `grep
         | -vE` and using the method you describe over several iterations
         | i end up with a history that has a lot of                   cat
         | log | not spam1 | not spam2 | not 'spam(3|4)' | .... | less
        
           | kqr wrote:
           | I really like that alias. Thanks!
        
           | mmh0000 wrote:
           | I've been using Linux for a very long time and never thought
           | of that as an alias. I love it! Thank you for sharing.
        
           | lambdaba wrote:
           | Zsh global aliases can be nice for commands commonly used in
           | pipelines:                 alias -g V='| grep -vE'
           | alias -g L="| $PAGER"
           | 
           | Then you can do                 cat log V spam1 V spam2 L
           | 
           | I also like                 alias -g G='| grep'       alias
           | -g X='| xargs'
           | 
           | The possibilities are endless...
        
             | TylerE wrote:
             | So are the injection possibilities. That makes me very
             | nervous.
        
               | lambdaba wrote:
               | What's the scenario?
        
               | TylerE wrote:
               | Something sets $PAGER to "rm -rf /" or something along
               | those lines.
               | 
               | Really I'd be more worried about _accidental_
               | invocations. Aliases are not scoped, so if you're dealing
               | with one of those programs with non standards option
               | handling and uppercase single character switches...
        
               | lambdaba wrote:
               | I actually use `alias -g L='| nvimpager'`,
               | 
               | As for accidental invocations, yeah I agree it feels
               | dangerous, but in a few hundred thousand lines of shell
               | history since I set them, never had a problem.
        
               | TylerE wrote:
               | Haven't had a problem, or haven't noticed you've had a
               | problem? I kid - but only partially.
               | 
               | What I really wish for is some sort of tool that would
               | let me pipeline like that, but also easily examine each
               | step in the chain for sanity. Sort of a workbook for
               | shell.
        
               | lambdaba wrote:
               | Auto-expanding aliases seems like it would help:
               | function expand-alias() {           zle _expand_alias
               | zle self-insert       }       zle -N expand-alias
               | bindkey -M main ' ' expand-alias
        
         | deathanatos wrote:
         | I've always though UUoC while working _interactively_ are fine.
         | One shouldn 't interrupt their flow to fix minutia in a one
         | time command.
         | 
         | UUoC criticism, to me, belongs when one sits down to script.
        
           | 0cf8612b2e1e wrote:
           | Eventually I will want to debug/change the script where we
           | get right back to the situation where I want cat at the front
           | of the line.
        
         | neuromanser wrote:
         | Press alt and dot (full stop) to insert last word from the
         | previous command line:                   $ cat file         $
         | grep stuff alt-.
         | 
         | Alternatively, make use off the READNULLCMD mechanism in Zsh:
         | $ < file
         | 
         | translates to                   $ ${READNULLCMD:-more} < file
         | 
         | Thus you can                   $ < file
         | 
         | then UP (or ctrl-p which I find more ergonomic) and continue
         | with "grep stuff":                   $ < file grep stuff
         | 
         | (Redirections can be anywhere in the command.)
         | 
         | https://zsh.sourceforge.io/Doc/Release/Redirection.html#Redi...
        
         | hawski wrote:
         | Try:                 < file.txt grep pattern
         | 
         | Less keystrokes.
        
       | matvore wrote:
       | If we're going to talk about unnecessary extra processes like
       | useless cat, we should merge the head and grep commands into a
       | sed, and possibly just merge everything into perl:
       | <access.log sed -n '/mail/p; 500q' | perl -e ...
       | 
       | If perl is processing the file line-by-line then filtering lines
       | by regex and stopping at line X is trivial, and you don't even
       | need sed.
        
         | jkingsman wrote:
         | I think your point is valid and I don't dispute it, but if I
         | had a nickel for every time I said "just do it all in perl" and
         | regretted it, I'd be... well, perhaps not a rich man, but I'd
         | have lunch covered for a few weeks.
        
           | matvore wrote:
           | Perl has the advantage of only having one implementation,
           | unlike sed and grep (e.g. BSD or GNU) and /bin/sh (can be one
           | of many POSIX shells), so upgrading this pipeline to 100%
           | perl is safer in some respects. The example in the article is
           | light on details so it's hard to comment very deeply.
           | 
           | I have heard snarky Perl putdowns ad nauseam at work and on
           | HN and may have regretted using it a handful of times but I
           | can say worse or similar for other popular tools,
           | languages...
        
         | b5n wrote:
         | I usually do it all in awk:                   awk '/mail/ && NR
         | <= 500 {...}' access.log
         | 
         | If you want N matched lines:                   awk '/mail/ && i
         | < 500 {i++; ...}' access.log
        
           | matvore wrote:
           | I wish I knew awk as well as I know perl, since then I
           | wouldn't need to hear recommendations for CPAN modules and
           | spurious style prescriptions.
        
       | txutxu wrote:
       | After read the article... all the reasoning... I think I could go
       | with this for such reasons exposed:                   perl -ne
       | 'last if $. > 500; /mail/ && print' access.log
       | 
       | When you're done with the part after the &&, remove the 'last if
       | $. > 500'
       | 
       | For me, the most useful use of (gnu) cat, is cat -A weird.file
       | 
       | It saves my day or solves weird issues (X-files) with files
       | generated by (not so) junior sysadmins, copy/pastes, end of
       | lines, invisible diffs, etc... many times each year.
        
       | cgs1019 wrote:
       | `cat -n` prints with line numbers, which is occasionally handy.
        
         | JTbane wrote:
         | nl?
        
       | nonethewiser wrote:
       | I like this sort of blog post - simple, clear example in a short
       | format. Of course we can nitpick the implementation but I think
       | the principle is solid: don't be afraid to sacrifice some brevity
       | for modularity or composability.
       | 
       | I do think he could have woven in the Parnas source a bit better.
       | The first quote seems to rely a lot on the surrounding context of
       | the essay and its never contextualized. This bit:
       | 
       | > The problem is that these subsets and extensions are not the
       | programs that we would have designed if we had set out to design
       | just that product.
       | 
       | Just feels a bit disjointed in the article. I get the high-level
       | message but thought it could be woven into the blog authors
       | narrative better. Anyways, it sounds like a good article though.
        
         | kqr wrote:
         | Author here. You're right. Originally I had a much longer
         | excerpt but it got a bit rambly. I overcorrected and cut out
         | too much; I'll see what I can do to fix it. Thanks!
        
       | cljacoby wrote:
       | I also use cat this way, and for me the biggest reason is it just
       | allows for a more intuitive left-to-right reading of any
       | pipeline.
       | 
       | Things like this:
       | 
       | head -n 500 access.log | grep ...
       | 
       | head -n 500 <access.log | grep ...
       | 
       | Feel like you start with the filename, then go leftwards to the
       | first operation, then start reading rightward again through the
       | pipe. At least in my brain, it feels slightly more awkward.
        
         | lubutu wrote:
         | You can do...                 <access.log head -n 500 | grep
         | ...
         | 
         | ... though that's less familiar to many, I'm sure.
        
           | cljacoby wrote:
           | Neat, I didn't realize you could order it like that.
           | 
           | I'm realizing now another (and potentially stronger
           | influence) is just years of muscle memory starting pipelines
           | with cat.
        
         | didntcheck wrote:
         | I wish math notation and computer programming had just settled
         | on postfix over prefix early on, it's so much more natural to
         | read. Of course, we kind of get it with object oriented
         | programming, some languages have UFCS [1], F# has that pipe
         | operator etc.
         | 
         | It's funny, when learning programming, I think Haskell was the
         | language that introduced me to the pattern of having a chain of
         | operators processing a stream to build up a result (and I'd
         | later cover it again in SICP), and I loved how clean it looked
         | compared to imperative code. But I now find it one of the
         | harder to read languages due to it all being prefix, whereas
         | Java/Kotlin/C#/Javascript now all have stream constructs that
         | use method calls, so read left-to-right, source-to-sink
         | 
         | And I'm reminded that I need to give Forth a proper go sometime
         | 
         | [1] https://en.wikipedia.org/wiki/Uniform_Function_Call_Syntax
        
       | az09mugen wrote:
       | Among the uses of cat, I saw no one mention you can write or
       | append text to a file, like this :                   cat >
       | file.txt  # after this command, just type your text
       | 
       | Or to append :                   cat >> file.txt
       | 
       | Can also work with Here Doc syntax :                   cat >
       | file.txt << EOF         This is the text to write down
       | EOF
        
       | jl6 wrote:
       | If only output redirection syntax was w> instead of >w. Then you
       | could write pipelines with compelling HTML-esque symmetry:
       | 
       | <x Y | Z w>
        
       | badrabbit wrote:
       | cat is cool but I also like it's sibling tac, I use it quite a
       | bit.
       | 
       | It's also possible to make a much faster cat (I have, considered
       | naming it cheetah),10%+ faster.
        
       | renewiltord wrote:
       | Honestly, I've being UUOC all my life and everything is fine.
       | Never run into a problem. I mostly use `zsh` and `< file | cmd`
       | works easily even when you remove the `cmd` so that's fine. But
       | honestly, it's both bought and lost me nothing, which means I
       | shouldn't care about it.
       | 
       | What I do like is doing something like:                   diff
       | -aui <(xxd binary1) <(xxd binary2)
        
       | charcircuit wrote:
       | I don't agree with this argument. You can make the same argument
       | against cat
       | 
       | >cat access.log | head -n 500 | grep mail | perl -e ...
       | 
       | >we find that cat performs two responsibilities:
       | 
       | >1. Printing an error to stderr if the file doesn't exist
       | 
       | >2. Copying a file to stdout
        
       | TacticalCoder wrote:
       | What's really useless are all the "useless use of cat" comments
       | (and shellcheck warnings although I take it for a shell script
       | there could be cases where one less process may be justified
       | [although really if you're at that point you've got other things
       | to worry than cat, sadly]).
       | 
       | I use "cat ... | ... | ... " like in TFA and just like many in
       | this thread because it simply makes sense. It's more intuitive.
       | It's easier to read. It requires less braincycles to remember how
       | this or that command wants its parameter passed, etc.
       | 
       | I think the "useless use of cat" movement made its time: it
       | failed. Many of us are never going to give up our use(less|ful)
       | of cat (you decide). So stop wasting your time complaining about
       | it.
        
       | psim1 wrote:
       | $ killall cat | cat | cat | cat | cat | cat
       | 
       | Terminated: 15
       | 
       | Which cat died first?
        
       | yesiamyourdad wrote:
       | I can't be the only one who clicked on this hoping for an
       | explanation of why they owned a cat.
        
       | VSpike wrote:
       | I definitely think if you want to use `cat` then just go ahead,
       | it's fine. Sometimes these things are a power play, a way to
       | distinguish between people who know the social codes and those
       | who don't. In this case, it probably had a reasonable origin even
       | if it's now more of a way to beat on newcomers. On old systems,
       | memory was limited, disk was slow and forking was expensive.
       | Saving a process in a script or one liner was a noticeable
       | improvement performance-wise.
       | 
       | I learned some bash from an old-timer who would write an
       | infinite-loop like this:                 while :; do          #
       | loop body here       done
       | 
       | This works because the `:` is a way to set a label, and it
       | implicitly returns 0. It's just a weird wrinkle of the language.
       | So, why not do `while true`? On old systems, `true` was not a
       | builtin and would call `/usr/bin/true`. Writing the loop this way
       | saves a process fork on each iteration.
       | 
       | On a modern system, you'd be hard pushed to measure the
       | difference, so it really doesn't matter which style you prefer.
        
       ___________________________________________________________________
       (page generated 2024-02-21 23:00 UTC)