Zsh is your friend.
mikegrouchy.com
mikegrouchy.com
(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))".
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 :)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-charFish 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.
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.
some 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.)
- shared history sounds like a bug, not a feature. I have long lived terminals open, each dedicated to a specific purpose. Shared history would intermingle them.
- typing `gut` in bash gives me:
No command 'gut' found, did you mean:
Command 'cut' from package 'coreutils' (main)
Command 'get' from package 'code-aster-run' (universe)
Command 'gout' from package 'scotch' (universe)
Command 'git' from package 'git' (main)
Command 'gpt' from package 'gpt' (universe)
Command 'gst' from package 'gnu-smalltalk' (universe)
You're batting 0/3. Certainly there must be some advantages to ZSH, but you haven't listed any yet.(Note that I didn't have to configure any of this. Ubuntu probably did, but I didn't).
The zsh autocorrect works much differently than what you have given. You have shown a feature of ubuntu (and probably debian) that looks for packages matching/close to your given command but what zsh does is give you, depending on your chosen settings, full autocorrect.
Where you may be able to type gut status and get No command found the setup in zsh would allow either for gut status to be autocorrected to git status or would ask you if you meant git status while waiting for a confirmation.
Zsh has floating point math, for instance $((1.0/2)) is 0.5 instead of an error. This comes in handy sometimes in simple scripts.
Zsh is significantly faster.
Zsh autocomplete is much more advanced. Bash may have copied the pid completion and some other easy ones, but zsh has all sorts of completion hooks, for instance "svn help ch<tab>" expands to "changelist". It also runs --help and parses out GNU style help text for completing options.
Zsh completion also has optional Windows-style cycle mode, so you can do "prefix<tab><tab>"... and cycle through the matches instead of prefix<tab>a<tab><tab>b<tab>-<tab>" like in bash. I think you can actually make bash do this but it's some obscure key binding.
...basically zsh is just a bit better at everything.
{edit: oops meant to reply to grandparent}
HIST_IGNORE_DUPS # don't add multiple 'cd ..', etc in a row?
HIST_EXPIRE_DUPS_FIRST # save unique hist entries longer
HIST_VERIFY # edit recalled history before running
INC_APPEND_HISTORY # add commands to .history immediately
EXTENDED_HISTORY # save timestamp on history entries
# set a huge history... doesn't seem to affect performance at all
HISTFILE=~/.zsh_history
HISTSIZE=10000
SAVEHIST=$((HISTSIZE/2))
For the completion I setopt AUTO_REMOVE_SLASH GLOB_COMPLETE MENU_COMPLETE NO_AUTO_LIST NO_BAD_PATTERN NO_BEEP NO_LIST_AMBIGUOUS NO_LIST_BEEP NO_NOMATCH, but I'm not sure what they all do ;-P
I prefer a long histfile (unlimited really, i. think i have it set to a million lines, but im at about 70 000. i even keep it backed up regularly because its fairly easy to trash the histfile if you are opening subshells and do the wrongthing. timestamped, too, which i find really handy.
that said, i do use and like zsh on my primary workstation, love it.. but i dont bother priming every other remote box with it, my bash config is simple and tweaked up just rightfor remote servers, and bash is there by default (dealing with older systems, etc.....i know zsh is installed by default often too)
Edit: Since I'm in ZSH company, here's the script: https://gist.github.com/1713414
# Append to ~/.bash_history instead of overwriting it -- this stops terminals
# from overwriting one another's histories.
shopt -s histappend
# Only load the last 1000 lines from your ~/.bash_history -- if you need an
# older entry, just grep that file.
HISTSIZE=1000
# Don't truncate ~/.bash_history -- keep all your history, ever.
unset HISTFILESIZE
# Add a timestamp to each history entry.
HISTTIMEFORMAT="%Y/%m/%d %H:%M:%S "
# Don't remember trivial 1- and 2-letter commands.
HISTIGNORE=?:??
# What it says.
HISTCONTROL=ignoredups
# Save each history entry immediately (protects against terminal crashes/
# disconnections, and interleaves commands from multiple terminals in correct
# chronological order).
PROMPT_COMMAND="history -a; $PROMPT_COMMAND"I was really looking for a different shell before. But if those are zsh killler features, it certainly wont be my choice.
Maybe I dumbed the post down too much, was just listing a few features that I use every day that IMO work better then the comparable Bash features.
Perhaps you should update it and add a number of the other features that you like about it (with a brief description..)?
(edit: spelling)
function command_not_found_handler() { /usr/bin/python /usr/lib/command-not-found -- $1 }
in your .zshrc
P.S.
This is obviously configurable, so if you prefer a different workflow, zsh will accomodate it.
1. Your feature comes from Ubuntu, not bash
2. More importantly, in ZSH if the correction is accepted by the user the command gets executed (with the fix) without any manual redoing. The correction can even be made permanent for frequent typos.
(and while I like ZSH a lot, shared history does tend to be a pain in the ass for me)
% time zsh -c exit
zsh -c exit 0.22s user 0.21s system 97% cpu 0.436 total
$ time bash -c exit
bash -c exit 0.00s user 0.00s system 83% cpu 0.004 total
Typing too early will just blackhole your keystrokes, of course, so no cheating!Or how about how when using an RPROMPT it makes copy/pasting stuff out of the terminal infuriate your IM buddies?
:)
Actually these are downsides, let's try fish instead, maybe?
% brew install fish
% fish
zsh: correct 'fish' to 'vis' [nyae]? GRRRAlso you can do stuff like /u/l/b and hit TAB.
This is possible in Bash too with bash-completion.
That being said, I'm a happy zsh user, for all it provides. Autocorrection is just one of the only things that, in my opinion, don't work well, so it's strange to market them.
setopt correct # try to correct spelling...
setopt no_correctall # ...only for commands, not filenames
https://github.com/samsonjs/config/blob/master/zsh/zshrc#L11...[...]
alias cp='nocorrect cp' # don't correct spelling for 'cp'
alias mkdir='nocorrect mkdir' # don't correct spelling for 'mkdir'
alias mv='nocorrect mv' # don't correct spelling for 'mv'
https://github.com/samsonjs/config/blob/master/zsh/zshrc#L20...I love having the shell as just another buffer right in the editor. Easy history searchability, copy and paste between code and various repls or SQL prompts, and all the other full editor features available at the prompt.
The last couple of days I've been trying terminal-mode rather than shell-mode, and it works much better. Many standard Emacs keybindings get remapped though.
There is also 'M-x serial-term' should you ever need it.
See http://www.masteringemacs.org/articles/2010/11/01/running-sh... for comparison.
Bash is probably more widely used because it was available earlier than Zsh, and because it was the "official" shell of the GNU project (better marketing).
ls -d ***/*(/)
than find . -follow -type d -exec ls -d {} \;I just spent a bit of time yesterday tweaking information in my prompt just so:
And it's made a huge quality of life difference to what I had before.
Worth spending a bit of time making your shell environment optimized for yourself though, and not just copying someone else's setup, in my opinion.
You spend a lot of time there, programming for UNIX, why not make it rock?
>scp server2:~/folder/* .
zsh: no matches found: server2:~/folder/*nothing in current work dir matches 'server2:~/folder/ * ', so zsh helpfully yells at me. yeah I know use single quotes to avoid expansion, and backslash should work too. It makes total sense because * is a reserved character, but still, bash got it. surely Zsh could've too ?
It probably got fixed since then, but this raw frustration is my most vivid memory from zsh usage.
setopt no_nomatch # if there are no matches for globs, leave them alone and execute the command
zsh also tries to autocomplete directory names using variables in global namespace that point to directories. I found that behavior maddening and can be turned off with: setopt no_cdable_vars # don't use named directories in cd autocompletionBut am really missing the Bash "help" command, and the combined (easily searchable) man page.
Thus far I have not been able to figure out which feature or config option to disable to stop this annoyance:
$ grep vim
zsh: correct 'vim' to '.vim' [nyae]?
Please don't "help me", i typed exactly what I wanted.
in your .zshrc
also run-help , I believe is the zsh equivalent to the Bash help builtin.
"run-help" doesn't seem to do the trick. As an example, in Bash, "help for" will describe the for loop construct. "run-help" seems to just be an alias for "man" and on my system calls up the Tcl for man page.
Thanks for the article and your response here.
Edit: I have setopt correctcall and I do not get this behaviour.
On an unrelated not, this is a classic example of complaining about why a product doesn't work and having users jump at the chance to fix your issue to prove it's worth.
But how to monitize this... :)
export HISTCONTROL=ignoredups
export HISTCONTROL=ignoreboth
HISTSIZE=50000
shopt -s histappend
PROMPT_COMMAND='history -a'
#history search inline
#bind '"\e[A": history-search-backward'
#bind '"\e[B": history-search-forward' zstyle ':completion:*' menu selectI am using oh my zsh but I tried turning it off and it didn't seem to matter.
Maybe only Mac users use zsh?
Thanks a lot.. works.
Is there something particular you are looking for?
I don't get the username either.
This post was intended as a nice introductory shoutout to Zsh. Oh-my-zsh is a great way for someone to get started with zsh if they wanted to try it out. It was never meant to be a complete guide to Zsh, and I wasn't going to list all the features, just a few that people who don't know anything about Zsh might be interested in.
But Hey, thanks for trying to give me a hard time. Stay classy.
oh-my-zsh is a great way for lazy people to get fancy features without having to look at the easily accessible manual ( http://zsh.sourceforge.net/Doc/ ) or even the user friendly guide ( http://zsh.sourceforge.net/Guide/ ).
I never said I expected you to list every feature. That's a pretty ridiculous hyperbole on your part.
I also wasn't "trying to give [you] a hard time". I was merely expressing my opinion. I'm sorry that you can't handle any criticism.
If you REALLY wanted people to adopt zsh, and grow the community, you should probably try to list some other things that you enjoy.
But Hey, thanks for trying to integrate yourself. Stay Classy.
All Mr. Grouchy did was give a couple examples of completion and oh-my-zsh. I think you would have to be really fed up with bash or whatever default shell your system has to take that bait. I never said I expected him to write a complete job. I just think there are better arguments to be made.
In fact, there are hundreds of posts on HN that give someone's evangelical tale of trying a new program, and several about zsh. This one is far from exceptional in my mind.
To me, it was like saying "You should buy a Tesla Model S because they are really fast."
That's the reason why I switched. Perhaps I'm missing something: what's wrong with 'oh-my-zsh'?