Shelljs – Portable Unix shell commands for Node.js
github.com
github.com
Just contributors.
(Unless you have some complicated install to perform which is good to avoid for multiple reasons.)
Edit: I know we're not supposed to talk about voting on HN, but really? -2 for saying "hey maybe NodeJS is actually kind of OK for some stuff" is wild.
And if you don't want it to do that then you have to start managing the concurrency yourself. I've never had to manage concurrency in a shell script beyond just making sure my crons don't run over each other if they take too long.
Async is incredibly easy to manage in node, even the simplest linter handles telling you you’re forgetting to await if you are.
This is what GP said, which is incorrect.
If Microsoft had only put all the PowerShell for Linux resources into Busybox.
MSYS2 is also pretty comfy. But that audience is probably better served by running WSL2.
Imagine installing windows powershell on debian because you don't know how to write unix shell scripts.
Care to elaborate?
I’m stuck with Windows for bean counting reasons, and though I resent it I feel I would benefit from actually learning to make full use of it. But maybe it’s not worth the trouble?
I think the lack of adoption in the Linux world is a mix of:
* Cultural (i.e. it's Microsoft) * Not included out of the box * Existing tools being 'good enough'
This is a wild statement
The only thing more remarkable than bash's cruftyness is the number of people who have developed Stockholm syndrome towards it.
Just read “in my opinion”.
That's the problem though. For me it totally sucks as an interactive shell because it's far too verbose. And if I needed to write scripts on Linux then I'm already spoilt for choice: Perl, Python, Tcl, Awk, etc are all usually pre-installed with my Linux distros. Then you can add Ruby, Go, Javascript (via Node), PHP, Rust, C++ and any .NET languages like C# into the mix too....plus many many many more.
While byte streams are largely seen as a joke compared to typed pipes like in Powershell and Murex, you do have far greater compatibility with byte streams since all you're sending is bytes -- which means you can write scripts in whatever the hell you want and still use them in Bash / Zsh just fine.
Then you have the 40 years of coreutils. People talk about legacy as being cruft and while there is some truth in that, there's also truth in the fact that if you need to do something in the command line, there's probably already a tool written which does it. That comes from maturity.
Don't get me wrong. There is a lot I'd like to change with regards to command line usage and shell scripting (and I'm working on that ;)) but Powershell throws the baby out with the bath water. Though in fairness to Microsoft, they never quite had a mature command line prior to Powershell so there was no baby to throw out. But for Linux usage....no thanks.
What do you mean? Busybox doesn't come with bash so it wouldn't work with bashisms.
[1] https://github.com/Kinto/kinto-http.js/blob/master/bin/dist-...
[2] https://github.com/Kinto/kinto-http.js/blame/6a4ba42ba13a91a...
If I run 'cat' in my shell I know it will print/output the file content.
If I run 'shx cat' I get an interpretation of my file content.
One use of 'cat' is to concatenate multiple files into one. Works great with classic cat, not so much with Shelljs.
$ echo -ne "\0xac" > test.dat
$ cat test.dat | xxd
00000000: ac .
$ shx cat test.dat | xxd
00000000: efbf bd ...
Biggest pain points in my opinion in pure bash is flow control, string manipulation, arrays, and looping.
You'd be amazed at how readable and un-gnarly most shell script become if you break them into functions. Control flow and loops become quite easy.
String manipulation on the other hand, if awk and jq can handle it reasonably well I'll use that, but I also forgive people for using a better scripting language. I prefer Ruby but I think using the language of the project is a better choice.
I have written some really basic shell scripts, and I try to use common shell modules/commands whenever it makes sense. It's just so confusing sometimes.
The main challenges I faced in the beginning where caused by MacOS. MacOS comes with an older version of Bash, its default shell ZSH comes with its own slight variations on how it expects you to do things, and the utilities that come with MacOS aren't Gnu so the available options/arguments are not what you would find online.
Then there is so much conflicting information online! A lot of it is also ancient, as in newsgroup archives from the 90s.
String manipulation. When I look up how to do some specific replacement again, I come across all these massive inline awk scripts. But then I remember I could also just use sed and regex, or in some cases even just standard variable tricks, and achieve the desired result with 90% fewer code.
The bigger scripts I've written are a mess.. I think. I still haven't been able to figure out how to error exit out of the entire script from a function that was called within it... :)
ShellJS is meant to be used from CLI, as native shell commands; zx is meant to run shell commands from JavaScript. There might be some overlap in usage, but IMHO ShellJS is useless unless you use Windows, while zx is useless if you know how to write bash code.
"Note that these aren’t Python functions, these are running the binary commands on your system by dynamically resolving your $PATH, much like Bash does, and then wrapping the binary in a function. In this way, all the programs on your system are easily available to you from within Python."
But there are still stuff I use bash for because it's way more efficient for one liners and small utilities.
One of the things is that calling something in bash autoprints, unless you pipe it. Could it be done in Python?
Well, it turns out you can, if you do a little dirty hacking with __call__, __repr__, __iter__, __or__ and __del__, you get:
https://0bin.net/paste/XeMvMuSh#45izWhAtQ5Bd14PDWoBqTJMvHZXa...
Which will let you do:
-ls('/etc'), auto prints all the files in the dir, in the shell and in a program.
- ls('/etc') | keep(r'\.conf$'), pipe the output of ls, pass it to keep, filter it, then auto print it (again, works in the shell AND in a py file)
- res = ls('/etc') | keep(r'\.conf$'), store the generator in the variable, doesn't print, doesn't calculate, ready to be able to be read with a for loop
This means we could create a lib with a very shell like experience in python for all those 5-lines-scripts that are still too good to pass bash for.
We could also make a @main decorator to auto run a function if __name__ == "__main__", borrow the "with cd()" and "with temp()" syntax from the fabric lib.
The need for bash would get smaller and smaller for me. I rarely develop on a linux box that doesn't have python, after all.
Now a problem people often hit is: yes, but you have to provide the dependency to your script. ShellJS proves that despite that, it has a great value already.
But the good news is, it's not a problem anymore thanks to a great features of Python 3: zipapps. With shiv (https://shiv.readthedocs.io/en/latest/), you can bundle your python script and all its dependencies (including our dirty shell lib) in a single pyz file, which then can run anywhere there is a modern python, which is everywhere I personally need it.
Another good use case is replacing bash/sh scripts. I know some times who have a rule that as soon as there's a conditional or a loop, you gotta switch from bash to a friendlier / less error-prone programming language. ShellJS makes node a pretty good option.
Nowadays, if you use ShellJS to replicate Unix commands, it means your team is mostly *nix users and you should probably just ask the rest of them to just use WSL and avoid a huge amount of problems that _not_ using it brings.