diff --git a/content/posts/nushell.md b/content/posts/nushell.md index 7522a65..4a87994 100644 --- a/content/posts/nushell.md +++ b/content/posts/nushell.md @@ -1,7 +1,6 @@ +++ title = "Nushell first impressions" date = 2024-03-01T11:34:04-06:00 -draft = true +++ Ive been trying out a bunch of new shell utilities lately, @@ -59,7 +58,7 @@ Some examples of things that nushell enables with this structured data passing through pipelines includes: {{}} -# show all files recurisively that were modified in the last week +# show all files recursively that were modified in the last week ls **/* | where modified > ( # create timestamp from relative human readable string. '1 week ago' | into datetime @@ -147,7 +146,7 @@ they take. {{}} def recently-modified [cutoff] { -# show all files recurisively that were modified after a specified cutoff +# show all files recursively that were modified after a specified cutoff # show all files recurisively that were modified after a specified cutoff ls **/* | where modified > ( # create timestamp from input @@ -160,7 +159,7 @@ You can optionally give the arguments a type {{}} def recently-modified [cutoff: string] { -# show all files recurisively that were modified after a specified cutoff +# show all files recursively that were modified after a specified cutoff # show all files recurisively that were modified after a specified cutoff ls **/* | where modified > ( # create timestamp from input @@ -174,7 +173,7 @@ with a type specification) {{}} def recently-modified [cutoff = '1 week ago'] { - # show all files recurisively that were modified after a specified cutoff + # show all files recursively that were modified after a specified cutoff ls **/* | where modified > ( # create timestamp from input $cutoff | into datetime @@ -189,13 +188,13 @@ absence) {{}} def recently-modified [cutoff: string = '1 week ago' --older-than (-o)] { if $older_than { - # show all files recurisively that were modified after a specified cutoff + # show all files recursively that were modified after a specified cutoff ls **/* | where modified > ( # create timestamp from input $cutoff | into datetime ) } else { - # show all files recurisively that were modified before a specified cutoff + # show all files recursively that were modified before a specified cutoff ls **/* | where modified < ( # create timestamp from input $cutoff | into datetime @@ -209,7 +208,7 @@ arguments. {{}} def recently-modified [--cutoff = '1 week ago' ...paths] { for $path in $paths { - # show all files recurisively that were modified after a specified cutoff + # show all files recursively that were modified after a specified cutoff ls $path | where modified > ( # create timestamp from input $cutoff | into datetime @@ -228,7 +227,7 @@ def recently-modified [ ...paths # paths to consider ] { for $path in $paths { - # show all files recurisively that were modified after a specified cutoff + # show all files recursively that were modified after a specified cutoff ls $path | where modified > ( # create timestamp from input $cutoff | into datetime @@ -271,8 +270,56 @@ but easy in POSIX shells. ## Error messages -Nushell brings with it great, self explanatory error messages. -For example, if we do this: +Nushell brings with it great error messages that explain where the error +occurred. In bash, if we have a loop like: +{{}} +$ for i in $(ls -l | tr -s " " | cut --fields=5 --delimiter=" "); do +echo "$i / 1000" | bc +done +{{}} + +This gets the sizes of all the files in kib. But what if we typo something? + +{{}} +$ for i in $(ls -l | tr -s " " | cut --fields=6 --delimiter=" "); do +echo "$i / 1000" | bc +done + +(standard_in) 1: syntax error +(standard_in) 1: syntax error +(standard_in) 1: syntax error +(standard_in) 1: syntax error +(standard_in) 1: syntax error +(standard_in) 1: syntax error +(standard_in) 1: syntax error +(standard_in) 1: syntax error +(standard_in) 1: syntax error +{{}} + +This error tells you nothing about what went wrong, and your only option is to +start print debugging. + +The equivalent in nushell would be: + +{{}} +> ls | get size | each {|item| $item / 1000} +{{}} + +If we typo the size column, we get a nice error telling us exactly what we got +wrong, and where in the pipeline the error and value originated. Much better. + +{{}} +> ls | get szie | each {|item| $item / 1000} +Error: nu::shell::column_not_found + + × Cannot find column + ╭─[entry #1:1:1] + 1 │ ls | get szie | each {|item| $item / 1000} + · ─┬ ──┬─ + · │ ╰── cannot find column 'szie' + · ╰── value originates here + ╰──── +{{}} ## Whats not there yet @@ -289,4 +336,39 @@ invoking them from within nu treats them as external commands, meaning they take in and pass out plain text, rather than the structured data that you would get with a proper custom command or nu builtin. -//explain the best workaround. +The best workaround Ive found so far is instead of making scripts that you run +directly, you define a custom command in the script file, `use` that file, and +then run the custom command, like this: + +{{}} +# recently-modified.nu +# display recently modified files +def recently-modified [ + --cutoff = '1 week ago' # cutoff to be considered 'recently modified' + ...paths # paths to consider +] { + for $path in $paths { + # show all files recursively that were modified after a specified cutoff + ls $path | where modified > ( + # create timestamp from input + $cutoff | into datetime + ) + } +} +{{}} + +{{}} +> use recently-modified.sh +> recently-modifiued --cutoff '2 weeks ago' ./ +{{}} + +Its certainly not the most ergonomic, but seems to be the best way at the moment +to make 'scripts' that are integrated with the rest of nushell. + +## So, overall, is it worth it? + +Nushell is certainly an interesting project, and I will almost certainly be +continuing to use it as my daily shell. It cant do everything, but dropping into +zsh for a task or two every once in a while isnt that big a deal for me, and +having access to such a powerful shell by default has made other tasks much +easier for me.