Fish is a great shell. It's a modern shell, that uses colors, UTF, and processing power that didn't exist when the others were designed. I feel the best thing about it is the sane defaults and large number of prebuilt completions. For any other shell, I have to dive into bashrc's and esoteric commands to get what I want. Fish just does what I want. It's made me far more productive, and for that, it gets my best shell award.
Its scripting support is good, very similar to other shells. Yes, the syntax is non-compatible, and not even POSIX. But, it makes more sense. Besides, for anything except the simplest of scripts, I use lua. I doubt you'd want to use bash to do something very complicated.
Some people want their shell scripts to be compatible and do a lot of cool things. I feel that the days of a shell being used for scripting are past. For me, a shell is a way of interacting with the system. Fish does this really well. Scripting is a slight afterthought, as it should be.
Popen is not the greatest because you can't get exit statuses from it. But for a quick script that is too messy in shell, it suffices. I believe that there is an extension to lua that has a popen that returns exit statuses. That can be used too.
For pattern matching, I either pipe to perl and capture the output, or use the inbuilt pattern matching system. It's surprisingly powerful.
You can also get the exit status using Lua 5.1 but it's definitely nasty (io.popen('your-command; echo $?') and the last line of output is the exit status).
For simple non-interactive scripts I still use bash because of its ubiquity, python for complex needs.
> I do like the shared history.
Maybe the implementation is different, but ZShell has shared history. (Just noting that this is not a 'fish rocks other shells because of X' feature)I've noticed this attitude among those who tend to use sysadmin-minimizing features of the internet, such as cloud hosting. There's still a whole world of real server out there, though.
I tend to use a shell for system interaction more than scripting. In that regard, I give more importance to interactivity enhancements. On the other hand, I have found myself using bash to automate simple things in our company testbed. As soon as I need a datastructure more than an array, or recursive functions, I jump to lua.
If your primary job is to be a sysadmin, then Bash is Required Reading.
My comment in reply to http://www.iheartchaos.com/post/16393143676/fun-with-math-di... is one example.
Configurability is the root of all evil
[1] http://fishshell.com/user_doc/design.html#confAs long as the people designing fish believe that, it will be unsuitable for people who want or need customized solutions. That describes a lot of people using shells now.
1. I use the Alt-. (dot) to get last argument of previous command.
2. Getting output of previous command such as : `!!` (backtick !! backtick) for which I get a "no such file".
I asked on reddit, but got no replies. Thx.
For that alt+. tip, I'd use the special $_ var.
It's incredibly powerful for interactive use and data manipulation combined with the standard Unix tools and sometimes pulling out perl or python is more work than just banging out a pipeline on the command line.
Quoting does take some time, but just remember that when in double to quote your variable expansions with double quotes. There's more too it, but that's a good rule to start with.
Here's a good bash FAQ. It contains questions like "how do I use associative arrays", with answers like "this is a complex question."
I don't even have to ask in any half-decent scripting language.
To use associative arrays in ksh:
typeset -A table
column="name"
table[$column]="value"
echo ${table[$column]}
ksh is much more decent than bash, although I reccommend using in an emacs M-x shell buffer for better command line editing.Edit: forgot to dereference column when setting value in table.
declare -A table
column="name"
table[$column]="value"
Included in recent versions of bash :)bash or zsh:
for i in `seq 1 100`; do echo $i; done
zsh: for i in `seq 1 100`; echo $i+1 for rc.
I mean, what about [[ ]] vs. (( )) vs. [ ]? Or the beginning of a case statement? Those always get me since I don't use them often enough for them to stick.
% which \[
/usr/bin/[
All of the other syntax is shell-specific (run via built-ins), so that can vary, and be a little more obtuse.[1] Albiet with some minor differences:
% if [ -d /tmp ]; then echo "TRUE"; fi
TRUE
% if test -d /tmp ]; then echo "TRUE"; fi
test: too many arguments
% if test -d /tmp; then echo "TRUE"; fi
TRUE
% diff /usr/bin/{test,\[}
Binary files /usr/bin/test and /usr/bin/[ differ
% man \[
No manual entry for [ $ 9 man rc | wc -l
496
$ man bash | wc -l
4890
Fewer interactive features as well, unfortunately. But it's small enough to keep in your head, and I find that makes it far more pleasant to use.rc really shines when you have problems that in bash or zsh would suggest using multiple layers of expansion. The semantics of rc's expansion is much less thorny.
I prefer real examples - here, why not just write
seq 1 100
- what is the loop for? And shell loops can frequently (always, if you are willing to write helper scripts) be replaced with xargs, which tends to be very much faster, e.g. seq 1 100 | xargs echo
(which doesn't quite give the same output, but passing -n1 to xargs fixes that)In bash: $array expands to the _first_ element of the array; you have to say ${array[@]} to get the whole array. And then you have to quote it in case one of the elements has spaces.
In rc: $array expands to the whole array, and the expansion is _not_ re-parsed, so if an element of the array has spaces in it, it is still considered a single element after the array variable expansion.
For this reason rc doesn't even need double-quoting; it only has single-quoting for escaping spaces in string literals.
It's like magic!
In bash, you can get it by adding the following to your .inputrc (at least on mac terminal)
"\e[B": history-search-forward
"\e[A": history-search-backward stty -ixon
lives in my init scripts for that reason.bindkey "^[[A" history-beginning-search-backward
bindkey "^[[B" history-beginning-search-forward
"\e[C": forward-char
"\e[D": backward-charsome shells that make excellent script languages are terrible for interactive use--a stock ksh, even ksh93, is pure torture for someone who grew up on bash and zsh and expects completion, history, a nice prompt, decent command editing, etc.
(i'm not sure if the reverse is precisely true, though certainly there are interesting programming features in ksh that are absent in zsh--discipline functions and so on.)
(Please forgive lack of backticks on my cellphone keyboard) Or many variations, like every line in a file, or result of a command piped to sed or awk and then processed. Init scripts are about the only shell scripts I write anymore, but I use frequently use it from the commandline, typically on remote terminals.
I now always use $(cmd) instead of `cmd`. Much easier to read and it fits in better with process substitution <(cmd). More importantly it all nests sanely $(cmd1 $(cmd2)) and works well in quotes "Blah: $(cmd1 $(cmd2))".