Nushell.sh ls | where size > 10mb | sort-by modified
nushell.sh
nushell.sh
> First and foremost, Nu is cross-platform. Commands and techniques should work across platforms and Nu has first-class support for Windows, macOS, and Linux.
Source: GitHub. No snark intended.
Do you? You need bash installed, certainly, but you don't need to learn bash in order to merely execute bash scripts. To use an analogy, just because your distro scripts things in Python doesn't mean one needs to learn Python to use the distro. I basically never need to write or read a bash scripts these days (I use fish, but I rarely write a real fish script either; just learn the language of your shell and YOLO).
It's a bit like the equivalent vim argument. Yes, using unmodified vim means you have access to the same tools in every environment. But I spend 99% of my time in one environment, so I'd like to optimise for that one, whether that's by using an IDE or installing a bunch of vim plugins and customising everything. Then when I do need to SSH into a server somewhere, I can get by on the bare minimum - in my case, usually nano. If I'm using nano for long enough that I start missing my IDEA features, then I've been using nano for too long and need to figure out a different way of deploying/debugging changes in the first place.
open foo.txt | append "world"| save --raw foo.txt
Oh.I love it!
It may seem a bit odd or even cumbersome to experienced shell programmers, but in my experience with Fish, this kind of thing helps a lot with ease of learning.
Fish is amazing!
I.e., there is no graceful scaling path.
I wonder how these other shells work with the backticks and such in Perl/Ruby. Theoretically there is room for very cool interoperability but I wonder how it goes in practice and if any nice tools and patterns are being developed.
And there's no hard constraint that would require this to "break down at some point". A well designed shell could also be a "real scripting language", all-in-one.
But the horrible CP/M and POSIX legacy of shell design doesn't help with that.
There are some old job control bugs, job control behaviors that used to not be POSIX compliant, and one outstanding bug having to do with IO redirection in fish functions that seem like they could be sort of relevant here. But there's nothing I can think of that I could interpret as 'lacking subprocesses'.
I only spent a few minutes looking into this, though. I'm curious to know if you can still recall more specifics, so many years later! Maybe there's something from before I started using fish that I've missed here. But fish is only 18 years old, going by the date of its first release, and I've been using it as a daily driver for ~13 years, and it has had everything I might call 'subprocesses' for that entire duration.
open foo.txt out> bar.txt 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
etcBut 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”.)
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.
> 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.
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;)`)
If you showed that without context it would look like some prefix/lispy notation so no, you are just showing how bad it is
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).
random-app < ./myfile.txt $ echo foo > a.txt
$ <a.txt ( echo bar >/proc/self/fd/0 )
$ cat a.txt
barSo, hiding the pathname from an untrusted tool via an unnamed pipe is a Posix security measure. Still bizarre!
Who was the guy who awarded UUOC prizes? Wasn't he a real dyed-in-the-wool security wonk?
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.
> 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.
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.
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
$ < 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 neaterI think this might hit the sweetspot for me, for dealing with json - I never could get a feel for "jq" like I have with sed/awk, and don't much enjoy powershell.
I don't think I need a new shell (bash is fine - and I would probably move to fish for a new shell if I were to change) - but I certainly need a sane way to wrangle json (hello docker inspect!) and yaml (hello kubectl/k8s and github actions!).
The great thing about shell languages is that you get to practice the scripting language with your everyday interactive usage, which is one of the main reasons I'd eventually like to switch, even if I see that perhaps the most exciting use cases are wrangling JSON and YAML in scripts.
For 99.99% of what I use a shell for, Nushell doesn't do anything that I can't do with a regular shell. Maybe just because I'm used to shells/sed/awk/etc.
For the few cases where Nushell could be useful, I can usually do the same thing with Vim/Emacs/VSCode or a trivial Python/Ruby script.
That is the question. Old habits hold us back from progress in usability. Eventually if one system is better it should completely replace the old system. But only if it's better. What one power user deems as "useful" according to his own usage patterns shouldn't be a metric for measurement.
I haven't played with nushell yet, but it actually seems more powerful then python for shell tasks. All the data structures are catered towards easy visualization and parsing parameters related to a shell. Python does not have such convenience.
However oh-my-zsh was pleasant to use as well!
Then they learn the better and end up having to learn bash anyway coz that's what runs on remote machines.
There is also not that much to be gained. Common easy tasks might be easier to learn but just few percent faster in the end. Harder ones are faster by one-off script in "real" programming language most of the time. Harder repeatable one should never be written in shell or shell-like language because it is just a terrible one to write any real programs.
Also if you really spend that much time gnobling in shell you'd be FAR better off investing time into learning configuration management tools.
Is that actually still an issue these days with Docker containers and what not? How often do you access a remote server via SSH where you share an account with your colleagues and cannot install another shell next to bash? (So that bash could still be the default but you could switch on the fly.)
And why you'd need bash fu just for local work ? The most I use it is for old fashioned servers (we have anything from "classics" to few k8s clusters)
Also, I've sometimes had to work on remote boxes on an internal-only network, with no outside internet access. In that case installing anything new is even more of a pain, so it's easier to work with the defaults as much as possible.
That said, I'm all for learning new tools. Progress couldn't be made if everybody just stuck with the old. But there's always a trade-off to be made between time investment into new tools vs. just getting your work done with the old ones.
About... almost every day?
unless you are the person to push for it to be installed on the remote machine.
The question is not "is nushell better than Bash" - it obviously is. The question is "is nushell better enough that you are willing to install it on every system you use, deal with naysaying colleagues and idiots that have been brainwashed into thinking Bash is great, learn a new tool, deal with all the incompatibilities with software that assumes everyone uses Bash, etc. etc."
As much as I hate Bash I would say it isn't that good. At least currently. If you're willing to install a new tool to run your scripts then there are better options, e.g. Deno. If it catches on and gets installed by default in more places in future (hopefully!) then that might change.
Basically I would say for interactive use Bash is not great but fine. For scripting use you shouldn't use Bash anyway.
A shell scripting language should also have a sort of convenience that allows the user to easily navigate and manipulate the OS via repl commands. Javascript while definetely a more powerful scripting language lacks the power of a repl OS command prompt.
Bash at the very least has the property of being good as a UI, even though it is clearly a horrible scripting language.
So nushell in this sense unionizes the best aspects of both worlds. Powerful UI, powerful scripting.
I suspect we’re both great at regexs. But scraping is brittle and trying to use it with object shells defeats the purposes.
open Cargo.toml | get dependencies | transpose | rename dep version | each { |row| let version = $row.version; if (describe $version) =~ "record" { $version.version } else { $version } }
open Cargo.toml | get dependencies | transpose | rename dep version | each { |row| if (($row.version | get -i version | default "" ) != "") { $row.version.version } else { $row.version } }
not sure whether that's the best way.
/s
I am curious though why you don’t count graal or .net aot? They are valid options to produce an aot binary and C# has been able to produce a self contained non-aot runtime for a long a time.
Great point, C# is a strongly typed and memory-safe language if you don't use unsafe. So this really is a huge advantage for PowerShell.
- Native support for JSON, etc (no more ConvertFrom-* ConvertTo-*)
- Less verbose
- Different visualisation
gci | where { $_.Length -gt (10 * 1024 * 1024) } | sort LastWriteTime
-gt might seem weird, but it’s better than overloading >.(Also, I like the fact that PowerShell is built into Windows and has a large corporation behind it.)
gci | ? Length -gt 10MB | sort LastWriteTimeShell has similar issues but I've put 20 years into it so the knowledge is there. Every time the PowerShell people describe PowerShell I think "that sounds awesome" but the ergonomics don't work for me.
Why is that test returning a boolean on the GP a block?
If I spent all day as a PowerShell dev I'm sure I would know it, but for something I reach for once or twice a year intuitiveness is a feature I would like to have.
find . -maxdepth 1 -type f -size +10M -exec ls -lt {} +
Or a very terse example: du -s -h * | sort -r -h | sed 10q
The thing is that if you're already used to POSIX-compliant shells then this is simply natural to write. Nushell has a different proposition of making it closer to natural language, which makes the learning curve much better. PowerShell just makes it different, but not really that much better.Also this is somewhat tangential, but I hate that PowerShell 5 and 7 are completely different things, and that PowerShell 5 is still the default even in Windows 11.
Oh yeah, and just for lols this is the same thing in zsh:
ls -lt *(.L+10240k)
By the way, I should note that it's possible to make the PowerShell example much simpler like the following: gci | ? Length -gt 10MB | sort LastWriteTime
The thing that really gets me here is the need to know aliases to keep it short, if you were to do it without the aliases it would look like this: Get-ChildItem | Where-Object { $_.Length -gt 10MB } | Sort-Object LastWriteTime
Also, again, case-sensitive commands make me mad.As for needing to know aliases... Did the knowledge that 'du' stands for 'disk usage' exist in your brain at birth, or did you have to learn it somehow? That criticism is nonsense.
At least with powershell, commands have a canonical, explicit name with standard verbs and nouns; and a short alias that's equivalent to the initial command in every way. What I also like is that parameters have aliases too: you can write - WhatIf or -wi and it'll work the same. And everything is documented.
https://learn.microsoft.com/en-us/powershell/scripting/whats...
Get-ChildItem | Where-Object { $_.Length -gt 10MB } | Sort-Object LastWriteTime `
It really gets you that you need to know aliases to keep it short? So why aren't you writing:
du --summarize --human-readable | sort --human-numeric-sort --reverse | sed --expression='10q'
`-exec ls -lt {} +` is not good because -exec is not handled by the shell so it behaves differently to running other commands, because `+` is a nonstandard command terminator, because {} is a nonstandard placeholder and because using `find` to run commands is an onion nobody would guess.In your terse example, `sort -h` depends on you having run `du -h` to trigger the matching "serialise information to text" and "parse information out of text" that they both need to make that one use work, because there's no separation of content and presentation (like PowerShell has) and no structured data to pass between different commands.
Not only will PowerShell tab-complete the names and the parameters, it will tab complete the properties Length and LastWriteTime because it can tell what objects come out of Get-ChildItem and what their available properties are.
> "Also, again, case-sensitive commands make me mad."
You do understand that du, find, sort, sed are case sensitive commands with case sensitive parameters, right?
It's not the best language for anything, but working a Windows shop, I'd rather bang stuff out in PS than grind my way through Visual Studio/C# for simple tasks.
- less verbose syntax
- better cross-platform support (PowerShell is technically cross-platform, but it has some baggage from its Windows-first history)
- way faster to start up
I'm biased (I'm a member of the Nushell core team), but those are all things that drew me to start contributing to Nushell.
On the other hand, Nushell is certainly less mature+stable than PowerShell. And if Windows administration is your main use case, PowerShell can't really be beat.
Powershell is kind of MIT-licensed, except for the parts that aren't but are still an integral part of it, so not really, and is therefore not Free Software. At least, it's not DFSG-free.
ls | where Length -gt 1mb | sort LastWriteTime ls | where { -not $_.PSIsContainer -and $_.Length -gt 1mb } | sort LastWriteTimeThe example is actually terrible though. It implies that changing the 10 to a string will make division a valid operation.
It’s also incredibly verbose.
https://github.com/multiprocessio/dsq
https://github.com/jqnatividad/qsv
https://csvkit.readthedocs.io/en/latest
https://github.com/kellyjonbrazil/jc
https://github.com/TomWright/dasel
https://github.com/johnkerl/miller
...
[zsh]$ ls -l *(Lm+10om)
zsh supports extended globs, this says: -l give me a long listing
“*(…)” of any file
Lm+10 who’s size “L” in megabytes “m” is greater than 10
“om” ordered by modification ascendingThis globbing functionality in zsh is separate from the ls command, so no ls magic here, but the ls builtin in zsh does have some useful extras in it all the same
It’s of course possible to do with existing shells, but it’s impossible to argue that it’s a clear
Or are you optimising for getting your thoughts transcribed to the machine as quickly as possible. It’s usually this case for me.
I tend to maintain a huge shell history so i really like the terse format for quickly filtering down my historical commands.
Writing shell scripts might be a good case for the longer form style although bourne-esque syntax is burned into my fingertips after all these years that long form is not going to be useful to me.
But sure, there’s a tension between readability and brain-to-command throughput that’s always been there.
The way you proposed is a bit too write-only for my taste, and the argument that you “had to learn it and now you’re muscle memory bound to it” is applicable to you only and does not preclude a better way from existing.
I put #tags at the end of long, opaque, reusable commands so that I can FZF search it quicker.
This was one of the biggest problems with Nu's dataframe functionality; it should be resolved now that we no longer ship with dataframes by default.
Totally agreed on dot method being nice for discoverability, that's something we need to do better on.
This is something we should communicate better in the docs, I'll see what I can do.
Returned back (from zsh) to fish this year and am super happy. Still the best built-in completion / history auto-suggest that I've seen in any shell so far, and super-fast at that.
Most importantly, barely any config needed (no needs for oh-my-zsh, prezto and all of those).
It's VERY refreshing, but I still have issues with it not short-circuiting when an error is thrown in a loop... Which I suspect will get fixed in time...
But doesn't it look like too monolithic? That will have problems with maintenance and scaling? And features that overlap with many already existing cli tools?
Happily, this includes import/conversion functions for new shells, so this plays nice with efforts like Nushell as well.
ls | where modified > (date now) - 1hr
> ls | where type == dir
or in Bash:
`ls -d`
> ps | where cpu > 0 | sort-by cpu | reverse
or in Bash:
`htop` ?
> ps | where name == Notepad2.exe > # find process, then ... > ps | where name == Notepad2.exe | get pid.0 | kill -9 $in
or in Bash:
`pkill Notepad2.exe`
> Pipeline content to clipboard
Or on MacOS:
`anything | pbcopy`
The first example is actually the only one that makes sense to me:
> ls | where type == file
Amazingly, there's no straightforward way to tell `ls` to output only files (that I know of):
`ls -p | grep -v /`
I don't mean to knock it, but I think it's better to learn the standard tools available everywhere than invest any time in tools that aim to lessen the learning curve.
`ls -l|grep -e^-`
Unless you meant without pipes/grep in which case I think no, but, you're bumping up against the fact that `ls` is really more of a user-presentation tool than for scripting. Use `find . -type f` maybe with some `-maxdepth 1`
When I show people the same advantage that PowerShell has over bash I pick harder problems where bash/gnu tools have no trivial answers. But then people get sour grapes and say “I don’t need to do that kind of thing anyway.” The reality of course is they avoid those harder problems and solve them manually or with different tools (Python).
Sorting is as good example, because while commands like ‘ps’ have some built in sorting capability, it is limited and inconsistent with other tools. You can sort by some columns, but not others. Sorting by the same field is often a different option across different tools even if they manipulate the same objects, etc…
If you would like a harder problem: kill every process on the machine run by the user “ash” that has used more than 1 hour of total CPU time but only those of his processes that are in the top 5 in the entire system by memory usage.
Hint: Don’t kill anyone else’s processes by accident even if their user name is “flash” or if their process name is “bash”. Also don’t confuse instantaneous %CPU with total CPU usage.
Did I say total CPU? Oops, I meant total kernel time used! My mistake. Update your a script, that should be a simple change… right?
I think this tool is useful for people who need to use the terminal right now, without having to spend quite a bit of time learning, e.g., Bash. Your point about the portability of Bash is, of course, valid. It just that sometimes you need to get stuff done quickly without parsing, at times unfriendly, documentation of more mature tools.
Dozens of specific commands and flags for specific usecases aren't always enough, and, dare I say it, counter to the UNIX philosophy.
For now, Homebrew works if you want a cross-distro way to install Nu on x64 Linux.
We also publish binaries: https://github.com/nushell/nushell/releases
I'm not likely to use brew on Linux (rather stow/xstow if I have to).
I was replying to your "Microsoft based" comment. And yes, powershell is also cross platform and open source.
Bigger isn't better my guy
Idk, I was an OG PowerShell, I'd take nushells approach every day of the week.
$ du -sh * | sort -rh
20M dist
6.9M pebble
1.5M internal
308K cmd
...I have, a few! But they are the kind of dev to never publish their work anywhere, not even little shell scripts. Secretive windows power users
To handle the transition to/from structured data, an idea I had was to omit one of the brackets in these names, so for example "ls[" would emit structured data but accept (well, assuming "ls" was a command that took stdin) an unstructured bytestream, and something like "]cat" would take in structured data on stdin but emit raw data... "cat[" would take raw data and... interpret it as JSON? or something? and output that as structured data? I don't know, it has to be fleshed out, but this could work maybe!
To get the JSON data back to a visual format like a table, we'd probably have to explicitly do what NuShell implicitly calls when you don't provide it (I forgot the name of it).
anyway, I haven't even begun a POC of this idea, but it was one I had. Anyone else like this idea?
It basically sits somewhere between Powershell and Bash: typed pipelines like Powershell but without sacrificing familiarity with all the CLI commands you already use day in and day out.
https://github.com/lmorg/murex
As an aside, I’m about to drop a massive update in the next few days that will make the shell even more intuitive to use.
(reading more) Super cool. Since it's Go, does that mean runtime errors will silently fail and keep chugging along? /dig ;)
Can you customize the PS1?
At the moment there is POC code to transmit over fd 3 but I’m looking into using UNIX sockets instead.
> Super cool. Since it's Go, does that mean runtime errors will silently fail and keep chugging along? /dig ;)
This project predates Rust 1.0 so it was a no brainier at the time to use Go. But actually I do think Go is well suited for this type of problem because much as some complain about errors being regular types, the way Go encourages granular handling of errors rather than larger try / catch blocks or exceptions does lead to more tailored error messages. Which ultimately helps explain the problem better for the end user.
Not taking anything away from Rust or any other language. Nor am I saying Go’s error handling doesn’t have its problems. Just that I’d probably choose Go again if I were to start this project tomorrow.
> Can you customize the PS1?
Every part of the shell is customisable. However rather than having hard to discover environmental variables that can alter the shells behaviour, instead there is a command called config that allows you to inspect every option.
I have. But they have never used bash, zsh, Fish, or NuShell.
Seriously though, for me their front page fails to give a convicing example how it's better than existing shells for a typical shell workflows.
Even the last one, which supposed to demonstrate better error messages, shows a cryptic error "change a or b to be the right types and try again". Perhaps type checking can help to say which argument is wrong and how to fix it? Now it's literally "one of your arguments is wrong, check man and try again".