Show HN: Sensible Bash: An attempt at saner Bash defaults
github.com
github.com
# From http://www.ukuug.org/events/linux2003/papers/bash_tips/
# Incremental searching with Up and Down is configured in .inputrc
"\e[A": history-search-backward
"\e[B": history-search-forward
... so if I type `ssh <up arrow>` I get the last command that started with `ssh`, not the last command I ran. oh-my-zsh thankfully does this by default as well. But I still use my .inputrc on server boxen where I don't want/need to install a different default shell.Also worth noting that all of those `bind` commands in OP's script are actually .inputrc lines if you remove the `bind` and surrounding quotes.
If I'm trying to semantically query my history (for "ssh") in this case I'll use the ^R binding to incrementally search the history, or literally grep ~/.history for what I'm looking for.
That's not to say that you're "wrong", just that calling these things "sensible defaults" is sort of missing the point. Nothing about them is sensible for everyone.
Once you get used to it, the only downside of up/down history search is when you ever use a shell that doesn't do it and you feel lost.
"\e[5~": history-search-backward
"\e[6~": history-search-forward
This allows you to continue using arrows for absolute chronological history then use PageUp and PageDn for history search.You could also change it to
"\e[5~": history-substring-search-backward
"\e[6~": history-substring-search-forward
if you want to search for a string match anywhere in the command rather than at the beginning. It might be 'substr' rather than 'substring' depending on your Bash version.Obviously the utility of this depends on your keyboard layout and config, as much as it does on personal preferences.
You can see the full list of commands at https://www.gnu.org/software/bash/manual/html_node/Commands-....
It mostly helps when you type complicated command and after half an hour you need to repeat it for some reason. You type the command you used, and hit a arrow up.
I'm pretty sure this is a solution to a problem I don't have today.
> Treat hyphens and underscores as equivalent;
> Automatically correct spelling errors during tab-completion;
I'm terrified to put this in my shell. Then again, it's not all-or-nothing:
> cherry-pick the options you like most ... everything is open for discussion
I had it in once (it's one the options in zsh setup)
Once I was cleaning my home directory:
rm -rf tec<Tab>
rm -rf IdeaProjects<Ret>
I'm a bit too quick to press enter after tab. So i deleted the wrong folder.I do still have it auto correct case. So `doc<Tab> -> Documents`
Also:
alias rm 'rm -i'(trash-cli sounds good, thanks for the tip)
I tend to create local scripts to initialize project environments using their root directory name. So the automatic prepending would make the action ambiguous as a command.
To each their own.
What's the rationality behind it?
I'm not a fan of adding features that make poor choices less painful, but I could see using it for a little while as I'm getting to know a non-ideal environment.
Just put "set -o vi" if you want to remove keystrokes, which this doesn't include.
And yes, even one keystroke saved matters.
I'm just somewhat of a cynic, since my workflow tends to fall on its face when I'm on a server that uses special snowflake rc files. Furthering that cynicism.. these days I'm just using plain /bin/sh for any shell scripts just because of the amazing level of bloat that exists within bash.
EDIT: groan, ok, you win. Net -1 keystroke for most keyboards.
Right now, someone (say, a bright 12-year-old) who opens up a terminal for the very first time and types "help" is greeted with this lovely mess:
compgen [-abcdefgjksuv] [-o option] > return [n]
complete [-abcdefgjksuv] [-pr] [-DE] > select NAME [in WORDS ... ;] do COMM>
compopt [-o|+o option] [-DE] [name ..> set [-abefhkmnptuvxBCHP] [-o option->
continue [n] shift [n]
coproc [NAME] command [redirections] shopt [-pqsu] [-o] [optname ...]
declare [-aAfFgilnrtux] [-p] [name[=v> source filename [arguments]
dirs [-clpv] [+N] [-N] suspend [-f]
disown [-h] [-ar] [jobspec ...] test [expr]
echo [-neE] [arg ...] time [-p] pipeline
enable [-a] [-dnps] [-f filename] [na> times
eval [arg ...] trap [-lp] [[arg] signal_spec ...]
exec [-cl] [-a name] [command [argume> true
exit [n] type [-afptP] name [name ...]
export [-fn] [name[=value] ...] or ex> typeset [-aAfFgilrtux] [-p] name[=va>
false ulimit [-SHabcdefilmnpqrstuvxT] [lim>
fc [-e ename] [-lnr] [first] [last] o> umask [-p] [-S] [mode]
fg [job_spec] unalias [-a] name [name ...]
for NAME [in WORDS ... ] ; do COMMAND> unset [-f] [-v] [-n] [name ...]
for (( exp1; exp2; exp3 )); do COMMAN> until COMMANDS; do COMMANDS; done
function name { COMMANDS ; } or name > variables - Names and meanings of so>
getopts optstring name [arg] wait [-n] [id ...]
hash [-lr] [-p pathname] [-dt] [name > while COMMANDS; do COMMANDS; done
help [-dms] [pattern ...] { COMMANDS ; }
user@host:~$Also recommend using something like Percol or fzf for filter-as-you-type command history.
Sane defaults, useful aliases, no dependencies and easy to expand upon. I made it mostly to give either a sensible default rc file to extend, or just a general high quality prompt.
edit: spaces add after asterisks to avoid formatting weirdness
zsh's default is much better. Though to be fair, bash-style passglob behavior can be enabled in zsh by setting NO_NOMATCH. zsh is still zsh, after all.
There's still plenty more wildcard nuttiness. A favorite is to execute a bare *: zsh will try to execute the first file, passing the other files as arguments!
Get zsh today. Give it a spin.
1) Glob qualifiers:
ls *(.)
will only match files, not directories, symlinks etc. ls **/*.jpg(.L-3000000on[1,5]) **/*.png(N)
will match .jpg files in the current and all subdirectories, which are: . files
L-3000000 with "length" (size) under 3MB
on ordering them numerically
[1,5] and only the first five
plus any .png files, if they exist (N = it won't fail if they don't).I have some scripts with expressions this complicated, but day-to-day it's useful for finding empty files (L0) or excluding directories. "man zshexpn" and search "Glob Qualifiers".
2) Glob operators:
ls DSC<100-200>.JPG
matches files with names between DSC100.JPG to DSC200.JPG. setopt extended_glob
ls *.java~*Test*
matches all .java files, except those matching Test*. Same man page, search "Glob Operators".3) Lazy for-loops (single command doesn't require do-done), and taking two variables:
echo "A 1" > tempfile
for i j in $(<tempfile); echo $i $j
4) Parameter expansion. > x=EXAMPLE.jpg
> echo $x:r.png ${x:r:l}.png
EXAMPLE.png example.png
Interactively, shell history seems to be nicer, I use a couple of global aliases (alias -g L='| less'), and the completion system completes everything you can possibly think of, like usernames, hostnames, remote filenames, HTTP URLs, processes (for kill)...Re number 2: That works in plain old Bash too:
ls DSC{100..200}.jpg > touch 1 3
> ls <1-3>
1 3
> ls {1..3}
cannot access 2: no such file or directory
1 3
Nevertheless, that's a useful and more powerful alternative to seq that I didn't know about.Tab completion is extremely powerful. Even serious spelling mistakes are forgiven.
The prompt is Git-aware and this provides a lot of helpful information which saves me from having to query the git cli.
There are also plugins available for completion of other programs such as rake
That's technically true for zsh in cases, but it's far easier to port or add compatibility for zsh than fish.
Today I learned people actually write / use scripts without specifying the interpreter at the top of the script. This is like writing a Ruby script and expecting it to work when calling it with the Python interpreter.
Upstreaming would also allow improvements, for example PROMPT_COMMAND='history -a' doesn't update history until the next prompt is displayed. If you close your terminal while a program is running then the last command entered is not saved.
I'm tempted to post my own commentary but I'd probably make the same mistakes. What would be really fantastic is a usability study of bash to see what the common pain points are.
grep = my_file
Also a problem is the syntax for running a program with environment assignments that apply only to the program: env1=foo env2=bar env3= my_program
Note that under POSIX rules, "env3" here is assigned a zero-length string. Making these sorts of assignments work with spaces around the equal signs would open up a can of worms.It always annoyed me that HISTTIMEFORMAT is not set by default. Without it, log entries are simply not timestamped at all.
The readline tweaks were news to me, thanks.
out of .bashrc:
function cd_func
This function defines a 'cd' replacement function capable of keeping,
displaying and accessing history of visited directories, up to 10 entries.
To use it, uncomment it, source this file and try 'cd --'.
acd_func 1.0.5, 10-nov-2004
Petar Marinov, http:/geocities.com/h2428, this is public domain
Just kidding, but not really, zsh is great and basically compatible with Bash, check it out.