Your Web News in One Place

Help Webnuz

Referal links:

Sign up for GreenGeeks web hosting
January 23, 2022 12:06 am GMT

100 Languages Speedrun: Episode 66: Xonsh

Unix shells were great for interactive use, but terrible for scripting, where you really should use a language like Python or Ruby.

There's been so many attempts at creating a better shell scripting language, like Elvish(https://taw.hashnode.dev/100-languages-speedrun-episode-48-elvish) I recently covered.

Xonsh decided to solve this problem once and for all by going "fuck it, Python is shell".

FizzBuzz

As Python in shell now, you can do this in Xonsh:

#!/usr/bin/env xonshdef fizzbuzz(i):  if i % 15 == 0:    return "FizzBuzz"  elif i % 3 == 0:    return "Fizz"  elif i % 5 == 0:    return "Buzz"  else:    return str(i)for i in range(1,101):  print(fizzbuzz(i))

There's not much point doing the usual examples, as you can just do pretty much any Python code, and it will generally just work.

Shell

When not used as Python, you have full shell environment too, with some reasonable autocomplete builtin:

$ git <TAB>    add             commit          maintenance     rm    am              config          master          send-email    amend           describe        merge           shortlog    apply           diff            mergetool       show    archive         difftool        mv              show-branch    bisect          fetch           notes           sparse-checkout    blame           format-patch    prune           st    br              fpush           pull            stage    branch          fsck            push            stash    bundle          gc              range-diff      status    cdiff           gitk            rebase          submodule    checkout        grep            reflog          switch    cherry          gui             remote          sx    cherry-pick     help            repack          tag    ci              init            replace         unstage    citool          instaweb        request-pull    up    clean           latexdiff       reset           wdiff    clone           log             restore         whatchanged    co              ls              revert          worktree

You can get some help with Wordle:

$ cat /usr/share/dict/words | pcregrep '^[^raton]{2}nce$'bunceduncefencehencemincepencesencesinceVincewinceyince

And so on.

How does it work?

Whenever you type anything, Xonsh checks if the code looks like Python or like Shell. And so it decides what to do.

You can explicitly request shell mode with $()

$ len($(seq 1 20))51

Or explicitly request Python mode with @()

$ say @(60+9)

This is a rare case where Python has an advantage over Ruby, as Ruby's flexible syntax would actually interfere with this autodetection.

What does not work?

Xonsh tries its best, but there's enough overlap between Python and Shell syntax that sometimes you need to disambiguate.

For example this doesn't work:

$ LC_ALL=ru_RU datexonsh: For full traceback set: $XONSH_SHOW_TRACEBACK = Truexonsh: subprocess mode: command not found: LC_ALL=ru_RU

Fortunately the alternative in this case isn't too bad:

$ $LC_ALL='ru_RU' date, 22  2022 . 23:23:01 (GMT)

Unfortunately some shell features don't seem to have any equivalent. One that I use a lot is redirect-from-command:

$ diff <(fizzbuzz.scala) <(fizzbuzz.cobol)

Xonsh comes with Bash to Xonsh Translation Guide, but it only covers basics. I really wished they extended it to more advanced examples.

Cat Facts

You can fix shell and Python in the same script without much trouble:

#!/usr/bin/env xonshimport jsondoc = $(curl -s "https://cat-fact.herokuapp.com/facts")for fact in json.loads(doc):  print(fact["text"])
$ ./catfacts.xshCats make about 100 different sounds. Dogs make only about 10.Domestic cats spend about 70 percent of the day sleeping and 15 percent of the day grooming.I don't know anything about cats.The technical term for a cats hairball is a bezoar.Cats are the most popular pet in the United States: There are 88 million pet cats and 74 million dogs.

SIGPIPE

Unfortunately this is completely broken in Xonsh. This is what we'd expect:

$ seq 1 1000000 | head -n 512345

If we write this Python/Xonsh script:

#!/usr/bin/env xonshfor i in range(1, 1000001):  print(i)

We get this:

$ python3 numbers.xsh | head -n 512345Traceback (most recent call last):  File "/Users/taw/100-languages-speedrun/episode-66-xonsh/numbers.xsh", line 4, in <module>    print(i)BrokenPipeError: [Errno 32] Broken pipeException ignored in: <_io.TextIOWrapper name='<stdout>' mode='w' encoding='utf-8'>BrokenPipeError: [Errno 32] Broken pipe

Now Xonsh should absolutely set up SIGPIPE handlers in its scripts to support this, as this is extremely basic shell programming pattern. It does not (and the error message is even worse). For as shell, I consider this a bug:

$ xonsh numbers.xsh | head -n 512345Traceback (most recent call last):  File "/usr/local/bin/xonsh", line 8, in <module>    sys.exit(main())  File "/usr/local/Cellar/xonsh/0.11.0/libexec/lib/python3.10/site-packages/xonsh/__amalgam__.py", line 21799, in main    _failback_to_other_shells(args, err)  File "/usr/local/Cellar/xonsh/0.11.0/libexec/lib/python3.10/site-packages/xonsh/__amalgam__.py", line 21746, in _failback_to_other_shells    raise err  File "/usr/local/Cellar/xonsh/0.11.0/libexec/lib/python3.10/site-packages/xonsh/__amalgam__.py", line 21797, in main    sys.exit(main_xonsh(args))  File "/usr/local/Cellar/xonsh/0.11.0/libexec/lib/python3.10/site-packages/xonsh/__amalgam__.py", line 21853, in main_xonsh    run_script_with_cache(  File "/usr/local/Cellar/xonsh/0.11.0/libexec/lib/python3.10/site-packages/xonsh/__amalgam__.py", line 3662, in run_script_with_cache    run_compiled_code(ccode, glb, loc, mode)  File "/usr/local/Cellar/xonsh/0.11.0/libexec/lib/python3.10/site-packages/xonsh/__amalgam__.py", line 3563, in run_compiled_code    func(code, glb, loc)  File "./numbers.xsh", line 4, in <module>    print(i)BrokenPipeError: [Errno 32] Broken pipeException ignored in: <_io.TextIOWrapper name='<stdout>' mode='w' encoding='utf-8'>BrokenPipeError: [Errno 32] Broken pipe

Should you use Xonsh?

Of the new shells I tried, I like Xonsh a lot more than Elvish. It works out of the box a lot better, with features like Ctrl-A / Ctrl-E, git completion etc. just working. The end goal of full support for Python is also much more ambitious than what Elvish is aiming for, and the learning curve is lower as you presumably already know some Python and Shell, so you'll just need a few exceptions Xonsh had to make to make them work together, not a whole new language.

I don't think Xonsh is ready to recommend it for serious use, but I'm really tempted to give it a go for a few weeks as my primary shell, and that's not something I felt about any shell in a long while. I expect a lot of early adopter pain if I go for it, but it's not like that ever stopped me.

Just the two biggest issues I ran into - no equivalent of <(...) and broken SIGPIPE - really stop it from being an acceptable shell now, so I hope they both get fixed soon.

Code

All code examples for the series will be in this repository.

Code for the Xonsh episode is available here.


Original Link: https://dev.to/taw/100-languages-speedrun-episode-66-xonsh-5ade

Share this article:    Share on Facebook
View Full Article

Dev To

An online community for sharing and discovering great ideas, having debates, and making friends

More About this Source Visit Dev To