Shell Productivity Tips and Tricks
blog.balthazar-rouberol.com
blog.balthazar-rouberol.com
:earlier 5m
and copied the line. Afterward, I typed :later 5m
and was back where I started, ready to paste the missing line :-) :later 8h
and commit the code before heading home. ;)It automatically makes a list of directories you frequently use in your shell and if you type `z a-small-substring-of-the-directory-path` it does a cd to that directory. (e.g. I type `z and` and it changes my current directory to $HOME/Work/Projects/android`). Saved me tons of typing.
export CDPATH="/path/to/my/projects:$HOME/Work/Projects"
# From anywhere.
cd andr<tab><enter>A huge block of "unalias" calls at the beginning of shell scripts used to be a common practice, but they don't seem to be found in more widely-used tools these days.
It's a bug in the script, just like reacting badly to $IFS or $LANG.
EDIT:
$ cat /usr/bin/cd
#!/usr/bin/sh
builtin cd "$@" $ cat /usr/bin/cd
#!/bin/sh
# $FreeBSD: src/usr.bin/alias/generic.sh,v 1.2 2005/10/24 22:32:19 cperciva Exp $
# This file is in the public domain.
builtin `echo ${0##*/} | tr \[:upper:] \[:lower:]` ${1+"$@"} yum install -y bash-completion
bash # a fresh runAnd zsh users get another advantage here. You can use assign to the cdpath array or the CDPATH colon-delimited string, they are both treated the same internally. The advantage is being able to `cdpath+=...`, much like adding to $PATH with `path+=` or removing from PATH with `path^=`. Check zshbuiltins(1) for how to make your variables work like this, or how to use typeset -U to remove duplicates automatically, or $thousand_other_cool_things.
Although I might adopt it for different weird system configuration directories which I often forget the path to.
[edit] Or z's based ageing ranking system will just aged those legacy directories, even better (in terms of more hands off)!
For example, I integrated it into ranger (see my history, I don't want to spam HN with this project).
No argument: start fzf (this really should read "to $(fzf)"), jump to that dir.
One arg: if the path is a real file/dir, jump to it, else use zoxide (z in rust) to soft-match it from history.
https://github.com/xkortex/bashbox/blob/master/aliases/core....
# use up and down arrow to match search history based on typed starting text
"\e[A": history-search-backward
"\e[B": history-search-forward
I also changed couple of setting wrt Tab autocompletion: # when using Tab for completion, ignore case
set completion-ignore-case on
# single Tab press will complete if unique, display multiple completions otherwise
set show-all-if-ambiguous onJust tag commands with a # at the end
> $ complex command here # tagHere
Later use the tag with ctrl+r
I do this all the time
> ssh 127.0.0.1 # master
and I think there are some fuzzy matching options (like fzf) that can be added to ctrl+r
I have since switched to zsh. Up/down to search history, in ~/.zshrc:
[[ -n "${key[Up]}" ]] && bindkey "${key[Up]}" history-beginning-search-backward
[[ -n "${key[Down]}" ]] && bindkey "${key[Down]}" history-beginning-search-forward
Autocompletion in zsh is a different beast altogether :)The primary reason I chose over zsh/bash was that autocompletion just works. If you install it, I highly recommend oh-my-fish as well, which allows you to add packages for look/functionality: https://github.com/oh-my-fish/oh-my-fish
If you're a zsh user, they have a similar framework: oh-my-zsh: https://github.com/ohmyzsh/ohmyzsh
I'm unsure whether minor differences that catch you out occasionally are worse than huge differences that you always have to think about. For me zsh still wins ;)
I think your comment will save my sorry ass one day.
It's not that it's impossible to be a shell polyglot, but GP deemed it easier to learn !fish.
I did install a similar history recommender in zsh and have been pretty happy with that.
The downsides have been mentioned, namely the lack of compatibility with shell scripts not written for it. In the same vein, until somewhat recently, operators like && did not work for it.
It’s still my daily shell, and I really only use something like bash when having to remote into a production server.
Zsh (with all the autocomplete plugins)
Oh-my-zsh zsh-autosuggestions: https://github.com/zsh-users/zsh-autosuggestions
Tmux
Histdb: https://github.com/larkery/zsh-histdb
Zoxide (replace cd): https://github.com/ajeetdsouza/zoxide
Fzf
Rip (replace rm): https://github.com/nivekuil/rip
My personal dotfiles: https://github.com/xkortex/bashbox
Mosh (replaces/augments ssh)
What I'm currently looking for is a better multi-host logging solution.
It’s already too late at this point. Anybody on your machine can read the commands you are running, for example with ps. You should instinctively avoid entering anything in plaintext into a terminal which you don’t want other people to see. Any command line tool worth its salt will provide alternative ways of passing secrets (using configuration files for example).
Most CLI programs that need sensetive information as input should either do it interactively (a la sudo), as standard input, or configuration file. If worst comes to very worst, you can put the sensitive info in a text file and use backticks. For example:
some-command --username=jedimastert --password=`cat secret.txt`This will not work in the way that you suggest. The output of ps will show the result of `cat secret.txt` and thus reveal the password.
With Perl, for example, assign to $0.
$0="what /bin/ps will see";
unset HISTFILE
exit
This prevents `bash` from updating the `~/.bash_history` file on exit with the command you don't want memorialized. (assuming you don't also have some hook that updates your history file after every command)So, a given config file can have permissions so that the file owner can read and write, but other users cannot. Like your ssh keys.
But ‘ps’ can be run by anyone, and it can typically access the whole command line you used.
This is why I always mount /proc with the "hidepid=2" option (as well as the "gid=<n>" option to ensure that doesn't apply to the members of a specific group, such as the "admins" of the box).
So if you do `date`, it'll end up in the history file but if you do ` date` (one space prefixed), it won't. One `clear` later and it's like the command was never run.
ctl-o ctl-o ctl-o re-execute the history one by one
alt-. alt-. alt-. last argument (better ux than that !$ business)https://github.com/ohmyzsh/ohmyzsh/tree/master/plugins/histo... looks through your history and only shows entries that started with the same characters that you already typed. Similar to Ctrl-R with fzf, but still similar enough that I use both.
https://github.com/zsh-users/zsh-autosuggestions also looks through your history for commands with the same start, but it will automatically suggest them for you to use. If you often use the same commands, this saves quite some typing. For bonus points, I hooked it up so that Ctrl-Return will execute the suggestion.
https://github.com/ohmyzsh/ohmyzsh/tree/master/plugins/per-d... To make the first two even more powerful, I split my history based on the directory I'm in. This means that it's only suggesting me commands I entered before in this directory.
**
is not "expanded to all files and directories in the children directories, with a depth limit of 1." It's hard to see using `ls` because `ls` doesn't just list its arguments, it also lists files inside its directory arguments. Use echo **
and you'll see it just expands to the same as *
- all the files in the current directory. Or type **
and press Ctrl-x, Ctrl-* (glob-expand-word) to expand it.After `shopt -s globstar`
**
expands to all files recursively.Also, `echo $dir | tr '[:lower:]' '[:upper:]'` should be `printf '%s' "$dir" | tr '[:lower:]' '[:upper:]'` to handle spaces and other weirdness in file names.
(If anyone knows how to escape asterisks in HN it would be helpful to know :)
Skim [0] is a nice alternative to fzf [1], mainly for the fact you can call additional commands dynamically like so [2]:
sk --ansi -i -c 'rg --color=always --line-number "{}"'
[0] https://github.com/lotabout/skim
[1] https://github.com/lotabout/skim#difference-to-fzf
[2] https://github.com/lotabout/skim#interactive-modeecho ${MY_VAR:-some_default} is another class of useful functionality.
$ sed -i '/secret-command/d' $HISTFILE # deletion of history line containing 'secret-command'
Because if you get it even slightly wrong, you could easily hose your entire history. If it were me, I would just use an editor to delete that line (or two, if timestamps are enabled).1. https://github.com/zsh-users/zsh/blob/master/Functions/Misc/... or zshcontrib(1)
I agree. That said I'll freely admit that liberal use of glob modifiers and qualifiers can lead to the appearance of line noise. Because of that I'll occasionally unroll them with `find(1)`-syntax if I post a snippet to help a co-worker, but love their expressiveness when in an interactive session.
For people not familiar with the extensive globbing options of zsh see https://linux.die.net/man/1/zshexpn .
Ctrl-a ctrl-k to clear the current command, or redo a hidden password prompt if you know you fat-fingered it.
ctrl-a jumps the cursor to the beginning of the line, and ctrl-k deletes from current position to the end of the line.
The mnemonic to remember these: "a" is the first position in the alphabet, and jumps you to the first position. "K" is short for "kill.”
It's incredibly easy (and transparent) to "install" and saves a ton of keystrokes.
But there's the truth in there that even programming languages that are 20 years old had a completely different mindset applied to their design process than the original Unix shell which was much more ad-hoc.
40 years ago IT was a completey different environment than 20 years ago.
'rename .txt _1.txt *' is quite a few lines in a language that's super simple, like Python, and it turns into code golf with even more terse languages.
I'll stick to the terminal.
mv is a simple executable. GP is talking about stuff like generating reports or sophisticated orchestration in .sh
Perl is maybe the closest here, but it certainly has it's fair share of annoyances, and I more or less dropped perl for python decades ago and don't particularly feel like going back.
shopt -s histappend
PROMPT_COMMAND="history -a; history -c; history -r"
See more about it here: https://unix.stackexchange.com/questions/1288/preserve-bash-...It occurred to me that every hack around history just nibbles at the edges probably because all of them are bolted on a design when the systems were slow. Systems now are fast and have good connectivity ( at least to themselves ) hence:
"All logins across all systems that have the same security domain share single common command history."
I use bash but it should be adoptable to anything. Here's how it works:
1. There's a database. I use redis because it is fast and has SETNX. [I may switch this to a redis queue to be able to archive commands as well.]
2. Using PROMPT_COMMAND variable I execute a function that pulls the last executed command using "history 1" and pushes it into the database. SETNX ensures that only a command that has not been seen before is stored. In the same transaction I trim the number of commands stored in the database to 5000.
3. Ctrl-R is bound to fetching last 5000 commands from the database, piping it into "peco" which I use with the selection line on a top ("fzf" does not support the top line so I don't use it here. "peco" does not support certain header skips/treatments, so i use "fzf" in other places )
4. On a failure to push into the database, system does nothing as the data is in a local history.
5. On a failure to pull from the database, system feeds the result of the local history into the "peco".
This system gives me ability to access the same command line history across my laptops, workstation, VMs, random Linux devices that i have running at home. Our ops-team uses it across all the monitoring workstations
Logging the entire bash history in files sorted by day: export PROMPT_COMMAND='if [ "$(id -u)" -ne 0 ]; then echo "$(date "+%Y-%m-%d.%H:%M:%S") $(pwd) $(history 1)" >> ~/.logs/bash-history-$(date "+%Y-%m-%d").log; fi'
I haven't overloaded ctrl-r yet to search in these files but that would be a possibility.
https://github.com/larkery/zsh-histdb
I haven't tried it, but the keywords you are looking for is bash history db/sqlite. E.g.:
https://github.com/thenewwazoo/bash-history-sqlite/blob/mast...
That's quite not what ^X^X does. The bash man page says:
Swap the point with the mark. The current cursor position is set to the saved position, and the old cursor position is saved as the mark.
export HISTSIZE=
export HISTFILESIZE=
for those wondering how to do it.)Sit down, and read through `man bash`.
Thank me later.
grep -n ... vi +§