The Linux Thread - The Autist's OS of Choice

  • 🐕 I am attempting to get the site runnning as fast as possible. If you are experiencing slow page load times, please report it.
I realise the below comment is going back a few weeks... but I didn't realise it when I started writing my reply. Accidentally just resumed the thread at the point I'd last looked at it. But have written it and will post it! :)

The real reason I prefer Linux isn't because it's problem free but because it has capabilities I appreciate that Windows does not. I use the terminal daily to do a variety of things that wouldn't be easy to do on Windows. Linux feels like/is a proper tool I can use to get what I want done, whereas Windows felt like dealing with an opaque bureaucracy that made its own decisions about what I was and wasn't allowed to do and I loathe it. Again it's about what you want to do with your system. The things I do are far easier (or even possible at all) on Linux than Windows so naturally I'm more happy with it.
I sort of want to debate you a little on this. I grew up on Bash and Vi and for a long time the lack of proper terminal, propert scripting and indeed needing OS elements exposed to be controlled even with those things, was a a major lack on Windows. That last one is wholly addressed as every operation and configuration of the Windows OS that I can think of is now exposed as an object. This is incalculably useful. As to the proper terminal and scripting well Windows terminal still has a few niggles that throw me. For example the lack of global history from session to session - it sort of has this but it's too clunky to get into here. Or that when I open a new tab it defaults to the initial location rather than wherever I am in the current terminal - which is how every Bash terminal I use is configured. And perhaps the biggest issue being that getting an in-terminal editor a la Vi is a nightmare. Though I've sort of made my peace with Visual Studio now (no I haven't). So I'm not here to evangelise the Windows terminal in a Linux thread - it still throws me. But it's decent enough and it certainly has a lot of features these days. But I would like to delve into the script side a bit more.

I will sincerely argue that Powershell is superior to Bash. Part of that is that Windows OS exposes every part of itself as an object and Powershell support for object pipelining as opposed to Bash's text mangling fits well with Windows whereas it wouldn't fit as well on Linux just as Bash isn't a good fit on Windows (sorry Cygwin).

But the other part is that Powershell really is functionally superior to Bash and infinitely more consistent. To take one simple example, how is it that the find command has a built in print formatter? Which is has different syntax to the actual print command? And don't get me started on Awk. Whereas lets say I want to format the output of something in Powershell? I could pipe a set of file objects from one command directly to the ConvertTo-CSV or ConvertTo-JSON cmdlets. Just the same as if I were reading a list of ACLs I could again pipe to ConvertTo-CSV or ConvertTo-JSON and know that these tools just receive the objects themselves, no text-mangling by the provider to control a format. It's all very logical and consistent and for the most part, easy enough to remember. It's ironic but Powershell actually follows the Unix philosophy of "Do one thing and do it well" much more than GNU tools do such as find.

In fact, lets roll with an example along these lines to show what I mean. I'm not trying to slate Bash, tbc. But I am challenging the idea that Windows limits you. I think working through some equivalents in both is interesting.

Lets say I want to recursively search the current directory for files containing a certain string. That's a realistic example. In GNU/Linux I'm looking at this:

grep -rl myString *

Straight forward enough if you know the commands. There are a few ways of doing this in PS but lets go with this:

Get-ChildItem -Recurse *.* | Where-Object { (Select-String 'myString' $_) } | Select-Object -Property FullName

First thing you notice? It's a lot longer. It's mostly fairly intuitive, though. Get-ChildItem isn't a name you'd guess if you had no familiarity at all but then neither is grep. And Get-ChildItem is at least consistent with the many other Get-* commands you'll learn.

The Where-Object is obviously a filter. It returns objects where the clause evaluates to True. I put a Select-String cmdlet in there. Again, not something you'd magically know but easy enough to remember and probably the only thing that really needs to be explained if you're unfamiliar with PowerShell is the $_. That's the placeholder for the input, like string interpolation. Easy enough concept for anybody who can use Awk. ;) :biggrin: In any case, this highlights the more modular nature of Powershell. People are so used to grep being both the file search AND the pattern matching that they forget they're really two separate operations. But it makes for more consistency and flexibility for operations to have separation of concerns.

Anyway to return to the example you could stop after the Where-Object command but you'd get back a list of file objects which might not have the formatting you want, e.g. would have timestamps, permissions, whatever. So I put a Select-Object -Property on the end which will get just the FullName, i.e. path and filename. Again, none of this is something you'd magically just know but it's all delightfully modular. I can send any object to the Select-Object -Property blah and have it handle the input. Or I could have the end piece be that ConvertTo-CSV that I mentioned, for example. Or whatever else. Contrast with Awk and its text slicing based on fragile text format.

Anyway, tl;dr: that's an equivalent in powershell to grep -rl mystring * in GNU/Linux. It's longer but arguably more intuitive and cmdlets expose their specifications to the shell itself so the terminal knows what parameters it supports so the terminal can underline errors, detect typos, handle autocomplete of them and so forth. Bash will autocomplete grep but it can't autocomplete the options because GNU/Linux commands aren't built in a standard way to have such definitions.

Anyway, lets go on a bit from there. Lets say I don't just want a list of matching files. Lets say I want their last modified date as well.

I'm going to have to fundamentally change my approach in GNU/Linux because the output of grep is just text in a specific format. It doesn't contain the information I need. I am rusty with Bash so if there's an easier way to do this let me know. But here's something getting not just the matching files but with their modified dates:

grep -rl myString | xargs stat -c %n':'%z | awk -F: '{print $1, $2}'

Here I'm having to text mangle and then feed the filenames back into another command and then the textual format of that command text mangled into another. The xargs section has to have its input in a specific expected pattern. I couldn't for example just swap in a different preceding command and know it would work. It's fragile. Ditto to the awk command, I have to have a specific textual input format. Lets contrast that with Powershell:

Get-ChildItem -Recurse *.* | Where-Object { (Select-String 'myString' $_) } | Select-Object -Property FullName, LastWriteTime

See, the sole change I made was to add an additional property, LastWriteTime onto the end and I can do that because I'm not passing text around but the actual file objects. Everything is already there and isn't sensitive to the particular text format used by some predecessor in the chain. Though if I did violate the robustness say, by passing an object that didn't have a LastWriteTime property, I would get a proper Exception raised which is better and I can handle programatically.

Lets take it further still. Lets say I want to search for matching files but only in those modified in the last twelve months. Again, it's a fairly simple and intuitive change in Powershell:

Get-ChildItem -Recurse *.* | Where-Object { (Select-String 'myString' $_) -and $_.LastWriteTime -gt (Get-Date).AddMonths(-12) } | Select-Object -Property FullName, LastWriteTime

All I've done is added an extra condition to the Where-Object filter. Job done. Lets see what's going on in Bash world:

Well again, I'm going to have to change my approach again I think. I don't want to filter on the end of my chain because firstly I probably have to write a full on Bash script and secondly that's not remotely performant to read everything in and just filter stuff out based on text at the end. So again tell me if there's a better way to do this but what I think is this:

find /directory -type f -mtime -365 -print0 | xargs -0 grep -l myString | xargs stat -c %n':'%z | awk -F: '{print $1, $2}'

Is there anything wrong with that other than it being long and maybe requiring you to remember some unintuitive command and formatting details? Actually yes - at each stage you're going back to the file system to request new information because it's just passing along text and each command is having to receive it, parse it, then use it to look up the actual file. Contrast that with Powershell where it accesses the file system once at the start and then just operates on it at each stage in memory (unless the list were *very* large).

So this post got a lot longer than I planned. It was going to be just a quick comment along the lines of "Windows can do this too" but then I decided to add an example to show what I meant and it got away from me. I know this is the Linux thread. I like Linux, I use Linux. Not meaning to start a Windows vs. Linux debate. They're both good. But Windows has caught up to Linux in many ways and I think some of the more devoted Linux users don't realise that. Honestly the main flaws with Windows these days are poor support for huge numbers of cores and, well, everything Microsoft forces into it for marketing / business reasons.
 
Thing is though, find and awk are external utilities and not part of bash, which is also only one of many available shells. If you have a better solution for these tools, you are free to use it. Or script one for your specific use case by gluing several, simple tools together, the Unix way. There-in lies the actual strength of the fairly heterogenous Linux ecosystem. If something doesn't feel intuitive to you, build a solution that is. I know this sounds failry "tl;dr" or dismissive, but is not meant that way at all. You can do some real magic. I notice it's something people coming from other OSes and workflows often don't seem to understand. They're always looking for one standard way to do things, one baseline, not understanding that it is often truly meaningless for the job at hand to have one. I'm sure some people will now come with the usual "I'm too busy and too professional and important and I can't be assed to do something like that" but to be honest, I've seen people spend insane amounts of time and energy on bizarre workarounds to force their proprietary OS of choice to do a thing a specific way, which would've never happened if they just used Linux.
 
grep -rl myString *

Straight forward enough if you know the commands. There are a few ways of doing this in PS but lets go with this:

Get-ChildItem -Recurse *.* | Where-Object { (Select-String 'myString' $_) } | Select-Object -Property FullName

First thing you notice? It's a lot longer. It's mostly fairly intuitive, though. Get-ChildItem isn't a name you'd guess if you had no familiarity at all but then neither is grep. And Get-ChildItem is at least consistent with the many other Get-* commands you'll learn.
Great, it's intuitive. I can remember `grep` though, I can't remember whatever on earth that is.

I sort of wish MS had just straight-up ported Bash, Powershell is far too wordy to be useful.
 
normal sane linux users writing why *blank* is good be like.

(that post is so fucking long the farms wont let me reply or quote it)
He dual boots Linux and Windows, even uses Visual Studio (a Microsoft-produced IDE) and is arguing that Microsoft Powershell is "functionally superior to Bash and infinitely more consistent". I don't necessarily agree but most of that was stated within the first (technically second) paragraph.
 
Great, it's intuitive. I can remember `grep` though, I can't remember whatever on earth that is.

I sort of wish MS had just straight-up ported Bash, Powershell is far too wordy to be useful.
I've only tried PowerShell using .NET Core and found the implementation lacking but still came to more or less the same conclusion with the small amount of experience I had with it. By the time I get to some of the examples @Overly Serious named, it's probably time I broke out Python.

I still never figured out how to use grep as every time I tried it's given me garbage or nothing at all
Can you give some instances of where you used grep and it failed? Some useful flags are -r ("recursive"), -i ("ignore case") and -v ("inVert match").

EDIT: It's worth noting that grep only deals with text file formats such as JSON. Utilities like zgrep, bzgrep and zipgrep can do a bit more but only with text that has been compressed.
 
Last edited:
Lets say I want to recursively search the current directory for files containing a certain string. That's a realistic example. In GNU/Linux I'm looking at this:

grep -rl myString *

No, the realistic example is
Bash:
find ./ -name "*myString*"


Is there anything wrong with that other than it being long and maybe requiring you to remember some unintuitive command and formatting details? Actually yes - at each stage you're going back to the file system to request new information because it's just passing along text and each command is having to receive it, parse it, then use it to look up the actual file
I think a lot of your issues come from just misunderstanding these commands or lack of knowledge. You don't need grep because find already has the -name option, and you don't really need xargs either

Code:
find /directory -type f -name "*myString*" -mtime -365 -exec stat -c ''%n: %y'' {}\; | awk -F: '{print $1, $2}'

Powershell also accesses the filesystem for every single file, it just does this at the beginning and then it works with the data in memory. There's no "get all data from this folder", you need to check the data in the folder to know what to get.

If you mean because you run stat, why are you doing that? Just as how you don't need grep or xargs, you don't need stat either. You also don't need awk. Find is a super powerful tool.

Code:
find ./ -type f  -name "*myString*" -mtime -365 -printf '%p %TY-%Tm-%Td\n'

And look at that, just one command. Even easier than powershell, no piping at all.


Sure, bash doesn't have objects, but there's absolutely nothing stopping you from working with other data types such as json, yaml, xml, csv, or whatever your heart desires.

Don't get me wrong, having objects can be cool and super useful, but there are very few times where not having objects actually impedes you, usually, just like in this case, people just don't know what tools to use or how to use them so they blame bash.
 
I've tried to get into Pharo (modern implementation of the legendary object-oriented language and programming environment Smalltalk) but what's often been hampering me is being unable to do things the Unix way
 
I think a lot of your issues come from just misunderstanding these commands or lack of knowledge. You don't need grep because find already has the -name option, and you don't really need xargs either
This is why people hate Linux users, if you don't know the difference between grep -r and find -name then you should probably just go back to a Commodore 64.

Look, Linux is so easy if you want it to do something entirely different than the the stated problem.
 
To be honest I think linux should probably always be the 'get filtered' operating system. Companies can always spin off stuff like android and steamOS for the retards and still cast darts at microsoft without niggerifying the userbase even further
 
This is why people hate Linux users, if you don't know the difference between grep -r and find -name then you should probably just go back to a Commodore 64.

Look, Linux is so easy if you want it to do something entirely different than the the stated problem.
You're right, I misread while skimming his wall of text and thought he wanted to search through file names rather than file contents. In this case he should just get rid of the first xargs and execute the grep directly in find.
Code:
find ./ -type f  -name "*myString*" -mtime -365 -exec grep -l 'string' {} + | xargs stat -c %n':'%z | awk -F: '{print $1, $2}'

Even so, Powershell does not make fewer filesystem operations, it makes the same amount. You still need to get a list of files and their metadata, open them all and search through them. There isn't any difference in what actually happens, just the order of operations.

I'd still argue the bash variant of this specific thing is much easier. Instead of having to do a comparison in your operation
Code:
$_.LastWriteTime -gt (Get-Date).AddMonths(-12)
you just write the time you want with
Code:
-mtime 365

But this is a pretty null point. Both powershell and bash are easy though and have more or less similar functionalities, and both can run on Linux.
 
But this is a pretty null point. Both powershell and bash are easy though and have more or less similar functionalities, and both can run on Linux.
Like I alluded to earlier, not everything works as it should on Linux. I had similar problems with using LINQ while following a C# tutorial using .NET Core. (Haven't tried Mono admittedly.)
 
I'm not sure what's up with the useless use of awk, but the proper, totally readable solution is:
touch --date='365 days ago' /tmp/365 ; grep -lr mystring mydir | xargs -I ^ bash -c '[[ ^ -nt /tmp/365 ]] && stat -c %n\ %z ^ '

I was going to try and do it in a Perl one-liner, but those braincells have gone missing.
 
Back