4 ms·
Historically we would discourage shell users from cat somefile.txt | whatever and instead tell them to use either whatever < somefile.txt or, if the
by codetrotter 4y ago
Historically we would discourage shell users from
cat somefile.txt | whatever
and instead tell them to use either
whatever < somefile.txt
or, if the command accepts input file names as arguments then use those like
whatever somefile.txt
or
whatever -i somefile.txt
etc
But perhaps in fish, “useless use of cat” is not so useless and would be recommended?
(I mean aside from the fact that they seem to recommend their “open” command, and so they probably prefer their own “open” over “cat”.)
- mtlmtlmtlmtl 4y agoFor some reason I never liked to do it the "right way". First of all it doesn't seem to actually matter. But most of all the cat way just aligns with my mental model more. Data flows left to right, if you catch my drift. It also makes it easier to add arguments to the end if re-running it.
- tomsmeding 4y agoWhile I get your point... > It also makes it easier to add arguments to the end if re-running it. I'd like to point out that a redirection doesn't have to be the last thing in a command. E.g. the common 'echo >&2 "some message"' works fine.
- Arnavion 4y ago>But most of all the cat way just aligns with my mental model more. Data flows left to right, if you catch my drift. Using `<` doesn't change that model. You can write `< somefile.txt whatever`. I always write my commandlines as `<in_file cmd1 | cmd2 | cmd3 >out_file` (Though annoyingly this doesn't work for feeding input to while loops. `< <(echo a; echo b; echo c;) while read -r foo; do echo "$foo"; done` is invalid syntax; it needs to be `while read -r foo; do echo "$foo"; done < <(echo a; echo b; echo c;)`)
- cerved 4y agodoesn't it work if you put it after the while but before the read?
- Arnavion 4y agoNo. That will execute `< <(...) read` anew for every loop iteration, which in this case will cause it to print an endless stream of `a`s.
- ilyt 4y ago> Using `<` doesn't change that model. You can write `< somefile.txt whatever`. If you showed that without context it would look like some prefix/lispy notation so no, you are just showing how bad it is
- Arnavion 4y ago"This thing I don't understand reminds me of another thing I don't understand, so it's bad I decided."
- ilyt 4y ago[flagged]
- mtlmtlmtlmtl 4y agoI thought it was an informative response. I certainly learned some stuff about shell I didn't know before. I'm still gonna use cat because it's simpler to me. I think your snark is unfounded here.
- alas44 4y agoI share the same opinion, I was made fun of with the "useless use of cat award" but find it so convienent to cat | grep then cat | grep | awk | wc then whatever with data flowing left to right and modifying the command sequence as I explore the file content.
- kccqzy 4y agoBesides it's also a fail-safe way to make sure the program doesn't modify the original file. random-app ./myfile.txt The app opens the file on its own. It could decide to write to it. cat ./myfile.txt | random-app The app receives chunks of the file from a pipe. It doesn't know where the original file is. This is especially useful if you aren't sure the program will by default modify the file (such as formatters).
- codetrotter 4y agoYeah but you get the same from random-app < ./myfile.txt
- a1369209993 4y agoOnly if random-app is well-behaved (and if you knew it was you could just use `random-app ./myfile.txt`). $ echo foo > a.txt $ <a.txt ( echo bar >/proc/self/fd/0 ) $ cat a.txt bar
- NoZebra120vClip 4y agoThat's bizarre and perverse! Surely someone has brought it up as a bug before that stdin is read-write! Is there some Posix standard preventing the standard shells from opening stdin as read-only???
- a1369209993 4y agostdin is readonly. `<a.txt ls /proc/self/fd/0` generally gives 'lr-x------' for the permissions. The problem is that having a open file descriptor to a file lets a program get and/or act-as-if-it-had a path to the file; /proc/self/fd/ is just the easiest way to do that.
- NoZebra120vClip 4y agoSo the thing is that this is a nothingburger. Just because you gave a pathname to an untrusted app means nothing. You've already trusted the app with your user account. It could already overwrite or vandalize that file no matter how you invoked it. Just because you indicate that file is special to you doesn't change anything in the threat model here. For all you know, the app could just traverse the entire directory tree and trash every file it could possibly write to, or just confine the damage to your $HOME. There's no reason IMHO to avoid using a file as an argument, or directly as stdin. If you don't trust an app, don't run it in your user account; you run it in a sandbox, right? This is 2023. Now a case could be made for defending against misbehavior by an app that might write to an fd by mistake, but as a1369209993 demonstrates, writing to stdin is a very deliberate choice, as you'll need to look up a pathname and deliberately open that file as writable. That's not misbehavior, that's malice, and that doesn't belong anywhere near your user account in the first place.
- scubbo 4y agoQuite. I had occasion to share this[0] in another thread, and it's relevant here, too: > When I offer a pipeline as a solution I expect it to be reusable. It is quite likely that a pipeline would be added at the end of or spliced into another pipeline. In that case having a file argument to grep screws up reusability, and quite possibly do so silently without an error message if the file argument exists. I. e. `grep foo xyz | grep bar xyz | wc` will give you how many lines in xyz contain bar while you are expecting the number of lines that contain both foo and bar. Having to change arguments to a command in a pipeline before using it is prone to errors. Add to it the possibility of silent failures and it becomes a particularly insidious practice. [0] https://stackoverflow.com/a/16619430/1040915 https://stackoverflow.com/a/16619430/1040915
- marcosdumay 4y ago> Historically we would discourage shell users from... For no good reason at all. It's not less confusing, and when shell programmers start talking about how wasteful it is to fork another process, it's because all the good explanations were already refuted. Also, it's worth pointing that this style was never unanimous. There is a very vocal minority that pushes for it, and a wide non-vocal majority that says basically "whatever, it's not like there's any difference" if you go and ask the question.
- mort96 4y agoThe use of cat is not useless. Having a "read this file" command be the source of the pipeline makes a lot of sense. It makes it seamless to replace the cat with a pv if you want progress, zcat if you're reading a gzipped file, curl if you want to use a URL, etc.
- codetrotter 4y agoFair point. But how often do you make those kinds of changes in any of your scripts and not have to change anything? For me, exactly 0 times
- mort96 4y agoQuite frequently? "Oh this operation turned out to take a while, I'll use pv instead of cat", or "oh what I grepped for wasn't in the current log, it's probably in the previous log that's gzipped, I'll replace 'cat current.log' with 'zcat previous.log'".
- asda22sdasd 4y agoSounds like you describe a interactive shell session, not stuff that happens in that script that was written for a specific purpose.
- coldtea 4y agoYou'd be surprised
- pseudalopex 4y agoThe 1st scenario and things similar to the 2nd happen in script development.
- version_five 4y agoI'm also a big fan of doing it the wrong way. (While I understand there is no practical difference) I find it more natural, because it's symmetrical (or parallel: $ < file util1 | util2 | util3 | ... The first util is the originator of the data pipeline, and it plus the file are the first command $ cat file | util1 | ... Each utility is it's own thing, being fed a data stream that came from cat. I know it's just personal preference but it feels neater