IPython as a System Shell
ipython.readthedocs.io
ipython.readthedocs.io
Shells are most successful when you don't need to think in order to use them. Especially since everyone that's used linux in the past 30(?!) years has the same basic foundation for how to use the command line, the best Shell will feel familiar to sh and bash, but better.
Math, logic, string and value manipulation, all those things I need to google because I don't remember whether an if statement in bash needs single [ ] or double [[ ]] or '' or "" or ; or spaces or all those weird gotchas.
I understand that many people do know how to program in bash effectively. That doesn't mean it's the future. It's like the Perl vs Python thread from the other day.
Xonsh is intuitive. Xonsh is well designed. Long live Xonsh.
This made me chuckle. A few years ago, I went on a learning spree to finally memorize all of these sparse semantics so I could write bash scripts fluently. I ended up having a really good grasp, could write scripts with no flailing.
Six months later, I was back to searching "bash double quotes vs single". Unless you use them every day, for years, these semantics just fall right out of your head.
Could you expand on this? I've been thinking about using a repl as a system shell. The piping issue is solved easily by sh.py. The main problem I can think of is startup latency.
if ls /path ; then echo foo ; fi
works just as well as the sugar wrapping "test" ( [ ] ) or extended builtins.
-- -- bash:~]$ if $var < 21; then echo "smaller"; fi
bash: 21: No such file or directory
-- -- BUT this works:
if (( $var < 21 )); then echo "smaller"; fi
smaller
-- -- BUT this DOESN'T:
if [[$var < 21 ]]; then echo "smaller"; fi
bash: 21: No such file or directory
-- -- BUT this DOES (added a space after '[['):
if [[ $var < 21 ]]; then echo "smaller"; fi
smaller
Plus the fact that having to type out 'then' and 'fi' and that semi-colons are semi-necessary are annoying. Compared to today's languages, very little of the non-posix parts of bash feel well though out. We can do better.
All these things make it necessary to understand bash. Most modern programming languages feel familiar. Bash and Sh don't anymore. They feel antiquated.
One of my biggest annoyances with shell is that there are these magic programs such as [ that pretend to be part of the language but aren't.
If if $var has an exit status (because perhaps you insanely want to have var be some program set elsewhere) your if statement would work....
These other examples have operators (test or similar expanded builtins), and those set the exist status that the if block reads.
so grep -q hacker < /etc/passwd if [ $? -eq 0 ] ; then echo hackd! ; fi
is an indirect way of saying:
if grep -q hacker < /etc/passwd ; then echo hackd! ; fi
Shell is terrible, but the way people use it makes it even worse because the sugar hides what's actually going on.
$ if (( $var < 21 )); then echo "smaller"; fi
smaller
$ if [[ $var < 21 ]]; then echo "smaller"; fi
smaller
$ if [[ $var < 21 ]] { echo "smaller" }
smaller"ls -la"
how does it know if it is "variable ls minus variable la", or "command list with command argument -la"?
This is horrifying. It can break in so many unexpected and context dependent ways... Do people really run this shell on purpose?
I ran it for a couple of years while I was in school, it worked great. I wouldn't run it on a production server, this is really for experimental work
I'm not sure how you end up rm -rf ing anything. 'rm -rf' by itself doesn't do anything, and if you do 'rm -rf .' that's no longer valid python. Not to mention that most people writing python would write 'rm - rf' if for some reason they had variables with those names (why would you name it that?) that they needed to subtract. And for some reason, you're not doing anything with the result of that subtraction.
If you're sourcing scripts without reading them, the source of the danger is that behavior, not your shell
I can see myself naming variables that way, when doing a geometric computation. Being a mathematician, all my variable names are single letters. But sometimes I have variants of a name that merit a second letter, like a sub-index. Maybe I use "r" for the current radius of an object and "rm" for the "middle" radius and "rf" for the "final" radius after some polishing process. Then I want to see how much material I'm losing from the object in the middle. Thus "rm -rf" (yes, the missing space is a typo).
ls -l
And this is arithmetic: (ls -l)
In general, parens delimit arbitrary Python expressions.[EDIT] Pr updating the docs https://github.com/ipython/ipython/pull/12894
(Otherwise, it looks great!)
I've inadvertently found myself using the IPython interpreter as my shell more and more. Opening vim in IPython always makes me smile. But I don't try to push it's abilities as a shell too much out of a healthy fear that it'll break unexpectedly in the worst way when I absolutely need it not to.
pretty nice if you know scala, still have to use regular shell(s) so I do not forget them
- no pipe/redirection mechanism
- high overhead in version/library control(pyenv, venv)
(All my personal preference, obviously. But I'd rather have any other language than python, even lua)
But I'm not convinced any high level language is a viable replacement for bash. It would have to be more functional than bash whilst still having good support for standard unix tools.
One very interesting idea I found was a macro library for racket that turns s-expressions from deeply nested structures into a much flatter representation. Lisp might be a good option with toy with because of flexibility like that.
https://www.reddit.com/r/Racket/comments/mands9/fluent_unix_...
seriously? lua shell won't even evaluate bare expressions
$ lua5.3
Lua 5.3.3 Copyright (C) 1994-2016 Lua.org, PUC-Rio
> 2*3
6
$ rlwrap luajit
LuaJIT 2.1.0-beta3 -- Copyright (C) 2005-2017 Mike Pall. http://luajit.org/
JIT: ON SSE2 SSE3 SSE4.1 AMD fold cse dce fwd dse narrow loop abc sink fuse
> 2*3
stdin:1: unexpected symbol near '2'
> =2*3
6file_list = !ls
delete_me = b[0]
!rm {delete_me}
Though it can't fit into a single statement due to a greedy '!'
Is this a standard anywhere outside IPython? I would love to use this sort of thing (python with seamless integration with a system shell) in place of bash scripts. Yes, you can use subprocess but it's a lot less readable.
Edit: Things like:
$output=`ls`;
$output=qx#ls -l#;
system('/bin/echo','avoid','subshell','invocation');
open("APIPELINE","ls -l |");
while (<APIPELINE>) {
chomp;
print "Got line: [$_]\n";
}
close(APIPELINE);
And access to child exit status in a way that's familiar ($?), etc.These days, Perl has 3 argument open, and can use a variable for a filehandle. So:
open(my $pipeline, "-|", "ls -l");
This is a good thing, because you can treat a filehandle as a standard variable, and can separate the special stuff from the command itself. This way if you're taking in user input, they don't get to mess with that. You can also do: open(my $pipeline, "-|", "ls", "-l", $directory);
Which lets you get away from the mess of correct quoting and just pass every parameter exactly as intended.[1] https://www.gnu.org/software/ed/manual/ed_manual.html#Comman...
[2] https://docs.julialang.org/en/v1/stdlib/REPL/#man-shell-mode
[4] https://docs.raku.org/language/quoting#index-entry-quote_qqx...
Having said that I think there is still room for modern shells which are easier to script in. For a while I am using fish and thought scripting would be at least as easy and straightforward as using lua. But the syntax is really awkward. For example comparing two variables needs to be put in a
math "2 + 2"
Urg.
I can hear the smalltalkers laugh from afar though
For example, custom history command to make early commands at the top, scroll to the bottom, and show the date and command on the same line
function hist; history -t -R | pyp '["\t".join(pair) for pair in zip(lines[::2],lines[1::2])]' | less +G; end; funcsave hist