Difference between revisions of "Linux shell/Bash prompt PS1, settings and history"
m (Pio2pio moved page Linux shell - Bash prompt PS1, settings and history to Linux shell/Bash prompt PS1, settings and history without leaving a redirect) |
|||
Line 179: | Line 179: | ||
export EDITOR="$VISUAL" | export EDITOR="$VISUAL" | ||
printf "\n | printf "\n[INFO] processing tab auto-completions scripts\n" | ||
command -v terraform && complete -C /home/vagrant/.tfenv/versions/$(terraform version | grep -oP 'Terraform v\K[0-9]+\.[0-9]+\.[0-9]+' | cut -d'v' -f2)/terraform terraform | |||
command -v gcloud && source /usr/share/google-cloud-sdk/completion.bash.inc # or /usr/lib/google-cloud-sdk/completion.bash.inc | |||
command -v vault && complete -C /usr/bin/vault vault | |||
command -v yq && source <($_ completion bash) | |||
command -v argocd && source <($_ completion bash) | |||
command -v cmctl && source <($_ completion bash) | |||
command -v flux && source <($_ completion bash) | command -v flux && source <($_ completion bash) | ||
command -v helm && source <($_ completion bash) | command -v helm && source <($_ completion bash) | ||
command -v kind && source <($_ completion bash) | command -v kind && source <($_ completion bash) | ||
command -v kubectl && source <($_ completion bash); alias k=kubectl; complete -F __start_kubectl k | command -v kubectl && source <($_ completion bash); alias k=kubectl; complete -F __start_kubectl k | ||
command -v kustomize && complete -C /usr/local/bin/kustomize kustomize | command -v kustomize && source <($_ completion bash) # complete -C /usr/local/bin/kustomize kustomize | ||
command -v minikube && source <($_ completion bash) | command -v minikube && source <($_ completion bash) | ||
command -v stern && source <($_ --completion bash) | command -v stern && source <($_ --completion bash) | ||
command -v vagrant && { VERSION=$(vagrant version | head -1 | cut -d" " -f3 | tr -d [:space:]); \ | |||
source /opt/vagrant/embedded/gems/gems/vagrant-$VERSION/contrib/bash/completion.sh; } | |||
# command -v tmux && source ~/.bash_completion_tmux | # command -v tmux && source ~/.bash_completion_tmux | ||
ISTIO_VERSION=1.10.0; ISTIO_INSTALL_DIR=/vagrant/istio-$ISTIO_VERSION | ISTIO_VERSION=1.10.0; ISTIO_INSTALL_DIR=/vagrant/istio-$ISTIO_VERSION | ||
[ -d "$ISTIO_INSTALL_DIR/bin" ] && PATH="$PATH:$ISTIO_INSTALL_DIR/bin" | [ -d "$ISTIO_INSTALL_DIR/bin" ] && PATH="$PATH:$ISTIO_INSTALL_DIR/bin" | ||
command -v istioctl && source $ISTIO_INSTALL_DIR/tools/istioctl.bash | command -v istioctl && source $ISTIO_INSTALL_DIR/tools/istioctl.bash | ||
unset ISTIO_VERSION ISTIO_INSTALL_DIR | unset ISTIO_VERSION ISTIO_INSTALL_DIR | ||
printf "\n | printf "\n[INFO] Adding function kube-events\n" | ||
kube-events() { | kube-events() { | ||
kubectl get events --all-namespaces --watch \ | kubectl get events --all-namespaces --watch \ | ||
-o 'go-template={{.lastTimestamp}} ^ {{.involvedObject.kind}} ^ {{.message}} ^ ({{.involvedObject.name}}){{"\n"}}' \ | -o 'go-template={{.lastTimestamp}} ^ {{.metadata.namespace}} ^ {{.involvedObject.kind}} ^ {{.message}} ^ ({{.involvedObject.name}}){{"\n"}}' \ | ||
| awk -F^ \ | | awk -F^ \ | ||
-v black=$(tput setaf 0) \ | -v black=$(tput setaf 0) \ | ||
Line 211: | Line 215: | ||
-v cyan=$(tput setaf 6) \ | -v cyan=$(tput setaf 6) \ | ||
-v white=$(tput setaf 7) \ | -v white=$(tput setaf 7) \ | ||
'{ $1=blue $1; $2= | '{ $1=blue $1; $2=yellow $2; $3=green $3; $4=white $4; } 1' | ||
} | } | ||
source /usr/share/autojump/autojump.sh # Read more at cat /usr/share/doc/autojump/README.Debian | |||
# ------------------------------------------------ | # ------------------------------------------------ | ||
</source> | </source> |
Latest revision as of 08:06, 27 November 2023
Google Shell style guide.
Dotfiles
There is a number of dotfiles in a user home folder that allows customizing working with terminal experience. They are:
- ~/.profile
- executed once when you login
- ~/.bash_profile
- scripts are executed for login shells, if exists Ubuntu won't source .bashrc
- ~/.bash_logout
- na
- ~/.bash_history
- the current session command history
- ~/.bashrc
- scripts are executed for non-login interactive shells
- Login shells
- are run with the user logged into the system. It's still an interactive session because you input commands and the shell reads them from its standard-input. You use login shells for anything where you need user permissions or where you would like the shell to start up with consistent configuration every time.
- Non-login interactive shells
- do not have a user attached to its session. These are good for running automated processes that don't depend on being logged in to run.
Generic
.profile
# ~/.profile: executed by the command interpreter for login shells. # This file is not read by bash(1), if ~/.bash_profile or ~/.bash_login # exists. Note, however, that we will have a ~/.bash_profile and it # will simply source this file as a matter of course. # See /usr/share/doc/bash/examples/startup-files for examples. # The files are located in the bash-doc package. # From here on out, I basically set up my PATH, LD_LIBRARY_PATH, and anything else I'd like # global to running programs and how those programs find their libraries. This is shared by # `cron`, so we really don't want interactive stuff, here. Also, I setup my environments # for brew, macports, and fink here, essentially with setting PATH, and invocation of those # package initialization file as in: # Brew and locally compiled stuff: export PATH=/usr/local/bin:$PATH export PATH=/usr/local/sbin:$PATH # The following line puts gnu utilities without the prefix "g" in the path # i.e. tar/gtar: export PATH=$PATH:/usr/local/Cellar/coreutils/8.21/libexec/gnubin # MacPorts shoves stuff in /opt, so to get at that stuff... export PATH=/opt/local/bin:$PATH export PATH=/opt/local/sbin:$PATH # Set up for using Fink, which lives in /sw: [ -e /sw/bin/init.sh ] && . /sw/bin/init.sh # My stuff: export PATH=~/perl:$PATH export PATH=~/bin:$PATH export PATH=.:$PATH
.bashrc
# ~/.bashrc: executed by bash(1) for non-login shells. # see /usr/share/doc/bash/examples/startup-files (in the package bash-doc) # for examples # If not running interactively, don't do anything [ -z "$PS1" ] && return # From here on out, I put in things that are meaningful to interactive shells, like aliases, # `shopt` invocations, HISTORY control, terminal characteristics, PROMPT, etc.
.bash_profile
# ~/.bash_profile: executed by the command interpreter for login shells. # Because of this file's existence, neither ~/.bash_login nor ~/.profile # will be sourced. # See /usr/share/doc/bash/examples/startup-files for examples. # The files are located in the bash-doc package. # Because ~/.profile isn't invoked if this files exists, # we must source ~/.profile to get its settings: if [ -r ~/.profile ]; then . ~/.profile; fi # The following sources ~/.bashrc in the interactive login case, # because .bashrc isn't sourced for interactive login shells: case "$-" in *i*) if [ -r ~/.bashrc ]; then . ~/.bashrc; fi;; esac # I'm still trying to wrap my head about what to put here. A suggestion # would be to put all the `bash` prompt coloring sequence functions as # described on http://brettterpstra.com/2009/11/17/my-new-favorite-bash-prompt/
My Dotfiles
Ubuntu 18.04, 20.04
Note: Note that in below configs .bashrc
is sourced before .profile
. So, any dependencies for autocompletion for tools that PATH is not set will fail.
.profile
# ~/.profile: executed by the command interpreter for login shells. # This file is not read by bash(1), if ~/.bash_profile or ~/.bash_login # exists. # see /usr/share/doc/bash/examples/startup-files for examples. # the files are located in the bash-doc package. # the default umask is set in /etc/profile; for setting the umask # for ssh logins, install and configure the libpam-umask package. #umask 022 # if running bash if [ -n "$BASH_VERSION" ]; then # include .bashrc if it exists if [ -f "$HOME/.bashrc" ]; then . "$HOME/.bashrc" fi fi # set PATH so it includes user's private bin if it exists if [ -d "$HOME/bin" ] ; then PATH="$HOME/bin:$PATH" fi # set PATH so it includes user's private bin if it exists if [ -d "$HOME/.local/bin" ] ; then PATH="$HOME/.local/bin:$PATH" fi # ------------------------------------------------ # Customized by Piotr # ------------------------------------------------ eval $(/usr/bin/ssh-agent) # set GOPATH if [ -d "$HOME/go" ] ; then export GOPATH=$HOME/go # path where go modules can be found, used by 'go get -u <url>' export PATH=$PATH:$GOPATH/bin # path to the additional 'go' binaries fi # set Gradle path export PATH=$PATH:/opt/gradle/gradle/bin export JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64 # Bash-my-AWS and its completions [ -d "$HOME/.bash-my-aws/bin" ] \ && export PATH="$PATH:$HOME/.bash-my-aws/bin" \ && source $HOME/.bash-my-aws/aliases \ && source $HOME/.bash-my-aws/bash_completion.sh [ -d "$HOME/.tfenv/bin" ] && export PATH="$PATH:$HOME/.tfenv/bin" # tfenv [ -d "$HOME/.okta/bin" ] && export PATH="$PATH:$HOME/.okta/bin" # okta-aws [ -d "$HOME/.krew/bin" ] && export PATH="$PATH:$HOME/.krew/bin" # krew kubectl plugin manager # tab completions [moved to .bashrc] # -----------------------------------------------
.bashrc
.bashrc
just customization that come at the end of file
# ------------------------------------------------ # Customized by Piotr # ------------------------------------------------ export PATH="$HOME/.tfenv/bin:$PATH" alias awsmfa='oathtool --base32 --totp $(cat ~/.aws/aws-mfa)' alias bat='batcat' # U20.04 apt-get installs bat as batcat as conflicts with 'bacula-console-qt' package alias vms='cd ~/vms-vagrant/u20cli-1' alias vpn=' ~/vms-vagrant/u20cli-1/git-host3rd/openvpn3-expect/vpn.tcl' # Eternal bash history export HISTFILESIZE=10000 export HISTSIZE=10000 export HISTTIMEFORMAT="[%F %T] " export HISTFILE=~/.bash_eternal_history # Force prompt to write history after every command. # Commented out as is dangerous, as in err you may run 'delete' from another window # PROMPT_COMMAND="history -a; $PROMPT_COMMAND" # Default editor export VISUAL=vim export EDITOR="$VISUAL" printf "\n[INFO] processing tab auto-completions scripts\n" command -v terraform && complete -C /home/vagrant/.tfenv/versions/$(terraform version | grep -oP 'Terraform v\K[0-9]+\.[0-9]+\.[0-9]+' | cut -d'v' -f2)/terraform terraform command -v gcloud && source /usr/share/google-cloud-sdk/completion.bash.inc # or /usr/lib/google-cloud-sdk/completion.bash.inc command -v vault && complete -C /usr/bin/vault vault command -v yq && source <($_ completion bash) command -v argocd && source <($_ completion bash) command -v cmctl && source <($_ completion bash) command -v flux && source <($_ completion bash) command -v helm && source <($_ completion bash) command -v kind && source <($_ completion bash) command -v kubectl && source <($_ completion bash); alias k=kubectl; complete -F __start_kubectl k command -v kustomize && source <($_ completion bash) # complete -C /usr/local/bin/kustomize kustomize command -v minikube && source <($_ completion bash) command -v stern && source <($_ --completion bash) command -v vagrant && { VERSION=$(vagrant version | head -1 | cut -d" " -f3 | tr -d [:space:]); \ source /opt/vagrant/embedded/gems/gems/vagrant-$VERSION/contrib/bash/completion.sh; } # command -v tmux && source ~/.bash_completion_tmux ISTIO_VERSION=1.10.0; ISTIO_INSTALL_DIR=/vagrant/istio-$ISTIO_VERSION [ -d "$ISTIO_INSTALL_DIR/bin" ] && PATH="$PATH:$ISTIO_INSTALL_DIR/bin" command -v istioctl && source $ISTIO_INSTALL_DIR/tools/istioctl.bash unset ISTIO_VERSION ISTIO_INSTALL_DIR printf "\n[INFO] Adding function kube-events\n" kube-events() { kubectl get events --all-namespaces --watch \ -o 'go-template={{.lastTimestamp}} ^ {{.metadata.namespace}} ^ {{.involvedObject.kind}} ^ {{.message}} ^ ({{.involvedObject.name}}){{"\n"}}' \ | awk -F^ \ -v black=$(tput setaf 0) \ -v red=$(tput setaf 1) \ -v green=$(tput setaf 2) \ -v yellow=$(tput setaf 3) \ -v blue=$(tput setaf 4) \ -v magenta=$(tput setaf 5) \ -v cyan=$(tput setaf 6) \ -v white=$(tput setaf 7) \ '{ $1=blue $1; $2=yellow $2; $3=green $3; $4=white $4; } 1' } source /usr/share/autojump/autojump.sh # Read more at cat /usr/share/doc/autojump/README.Debian # ------------------------------------------------
prompt (PS1
)
PS1
variable holds the value of our shell prompt. It's often defined in ~/.bashrc
. These steps have been tested with Ubuntu 14.04 LTS, 16.04 LTS, 18.04 LTS, 20.04 LTS:
- edit vi ~/.bashrc
- Uncomment #force_color_prompt=yes
sed -i -E 's/^#(force_color_prompt=yes)/\1/g' ~/.bashrc
- Find
if [ "$color_prompt" = yes ]; then
statement - Update
PS1=
to your liking or as per examples below
Note: Because gcloud
command it takes around 1-2sec to startup, the function has toggle based on environment variable PS1_GCP
. Set the variable to show GCP Project in the prompt.
# Terraform workspace terraform_workspace() { [ -d .terraform ] \ && printf '%s' " t[$(command terraform workspace show 2>/dev/null)]" } # GCP project name gcp_project_name() { local GCP_PROJECT [ -n "$PS1_GCP" ] \ && { command -v gcloud &> /dev/null \ && GCP_PROJECT=$(gcloud config get-value project 2> /dev/null) \ && [ -n "$GCP_PROJECT" ] && printf '%s' "gcp[${GCP_PROJECT}]"; } } # Kubernetes context kubernetes_context() { local CONTEXT command -v kubectl > /dev/null && CONTEXT=$(kubectl config current-context 2> /dev/null) \ && [ -n "$CONTEXT" ] && printf '%s' "k[${CONTEXT}]" } # Git branch git_branch() { [ -d .git ] && printf '%s' "($(git rev-parse --abbrev-ref HEAD 2> /dev/null))" } PS1='${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\] ' PS1+="\[\e[1;34m\]\$(gcp_project_name )\[\e[0m\]" # blue PS1+="\[\e[1;32m\]\$(terraform_workspace)\[\e[0m\]" # green PS1+="\[\e[1;33m\]\$(kubernetes_context )\[\e[0m\]" # yellow PS1+="\[\e[1;32m\]\$(git_branch )\[\e[0m\]" # green PS1+='\$ ' #PS1='${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$ '
Coloring considerations:
- Coloring is best to apply directly to PS1 variable, otherwise window wrapping may cause problems,
- check your terminal matrix compatibility
- PS1 bashrcgenerator.com
- terminal-prompt-not-wrapping-correctly
- important is to enclose non-printable sequences into
\[
and\]
brackets - verify
shopt checkwinsize
ison
if not enable byshopt -s checkwinsize
- The reason for the behavior is because bash believes the prompt is longer then it actually is. As a simple example, if one use:
PS1="\033[0;34m$" 1 2345678
the prompt is believed to be 8 characters and not 1. As such if terminal window is 20 columns, after typing 12 characters, it is believed to be 20 and wraps around. This is also evident if one then try to do backspace or Ctrl+u. It stops at column 9. However it also does not start new line unless one are on last column, as a result the first line is overwritten. If one keep typing the line should wrap to next line after 32 characters.
- important is to enclose non-printable sequences into
Kubernetes prompt
(<symbol>|<context>:<namespace>) # the default prompt layout (<symbol>|N/A:N/A) # context not set
Reload shell without logging out
. ~/.bashrc source ~/.bashrc exec bash exec "$BASH"
Differences
- source ~/.bashrc will preserve your current shell. Except for the modifications that reloading ~/.bashrc into the current shell (sourcing) makes, the current shell and its state are preserved, which includes environment variables, shell variables, shell options, shell functions, and command history.
- exec bash, or, more robustly, exec "$BASH"[1], will replace your current shell with a new instance, and therefore only preserve your current shell's environment variables (including ones you've defined ad-hoc). In other words: Any ad-hoc changes to the current shell in terms of shell variables, shell functions, shell options, command history are lost.
[1] exec bash could in theory execute a different bash executable than the one that started the current shell, if it happens to exist in a directory listed earlier in the $PATH. Since special variable $BASH always contains the full path of the executable that started the current shell, exec "$BASH" is guaranteed to use the same executable.
Bash auto completion | autocompletion
Debian based
sudo apt-get install bash-completion
RPM based distros
Amazon Linux AMI. Version 2 has epel repo (Extra Packages for Enterprise Linux) enabled
# CentOS or RHEL 6.x sudo yum-config-manager --enable epel # CentOS or RHEL 7.x sudo yum install -y epel-release sudo yum repolist # verify epel sudo yum install bash-completion bash-completion-extras # RHEL8 sudo yum install -y bash-completion
Bash coloured autocomplete of symlinks
Use bash --version | grep release
to find out what version of Bash you are using.
To configure it add lines below to your ~/.inputrc
or system-wide /etc/inputrc
Bash 4.3 readline adds a variable that enables color for tab completion to show different colors for executable files, directories, etc., during tab completion. Readline in the upcoming Bash 4.4 adds a variable which enables colour to indicate the matching portion of the string during tab completion.
set colored-stats on #bash 4.3 set colored-completion-prefix on #bash >=4.4
You can see the values of these variables using
bind -v | grep color
Bash autocomplete and common string with ellipses
Add to your ~/.inputrc
or system-wide /etc/inputrc
file
set completion-prefix-display-length 2
When you TAB to autocomplete the common string if it's longer than 2 characters will be replaced with (...) ellipses
Bash key binding, cli shortcuts
CTL
+a
- move to BOLCTL
+e
- move to EOLALT
+f
- move one word to right (forward)ALT
+b
- move one word to left (backward)CTL
+u
- erase line to the left/BOLCTL
+k
- erase line to the right/EOLCTL
+w
- erase one word to the right (forward)ALT
+d
- erase one word to the left (backward)CTL
+t
- switch characters places, with a character behindCTL
+r
- reverse search of historyCTL
+s
- forward search within historyCTL
+p
/n
- scroll through historyup
/down
- ALT-Shift-.: Jump to the end of the history (most recent)
- ALT-Shift-,: Jump to the beginning of the history (most distant)
CTL
+l
- clears screen
Escape sequences
ESC
+.
or!$
or!_
- is last argument of the last command
Replace last command strings
echo "first command" && echo "second command!" !!:gs/command/echo #call last command and substitute word "command" with "echo" first echo second echo!
- Readline This is what allows for all bash key bindings, colouring etc..
Bash history
- History-Interaction Bash GNU manual
Key bindings in bash shell
CTL
+r
- reverse search of historyCTL
+s
- forward search within historyCTL
+p
/n
- scroll through historyup
/down
ALT
+Shift
+.
: Jump to the end of the history (most recent)ALT
+Shift
+,
Jump to the beginning of the history (most distant)ALT
+.
orESC
+.
-recall the last argument of any of the previous commands
Event Designators and Word designators
- Event Designators
- is a reference to a command line entry in the history list. Unless the reference is absolute, events are relative to the current position in the history list.
- Word designators
- are used to select desired words from the event. A
:
separates the event specification from the word designator. It may be omitted if the word designator begins with a^
,$
,*
,-
, or%
’. Words are numbered from the beginning of the line, with the first word being denoted by 0 (zero). Words are inserted into the current line separated by single spaces.
!*
all previous arguments, eg.ls /tmp; cd !*
!!
recall previous command (often pronounced "bang bang")!n
command number n from history, eg.!-2
!pattern
recall recent command matching pattern, eg.!vi
!!:s/find/replace
recall last command, substitute find with replace, also!!:s^find^replace
works$_
last argument from previous command$_
last command's all arguments, allows call new command with previous command arguments!^
and!$
^first and last$ argument (after the program /or built-in /or script) from previous command!!:0
- recall the previous command itself (just a command)!!:0- hf
- reproduces the previous command substituting "hf" for the last argument!!:1
,!!:2
recall previous command with n-number argument; examples
command with n-number argument | n-command with n-argument | re-call all args new command |
---|---|---|
$ touch {a,b,c}.sh $ ls a.sh b.sh c.sh $ ls !:2 ls a.sh a.sh $ ls !:2-3 ls a.sh b.sh a.sh b.sh |
.2075 ls a.sh b.sh c.sh #-3 2076 cd a.sh b.sh c.sh #-2 2077 history #-1 #take the first arg from the 3rd last command history $ ls !-3:1 ls a.sh a.sh 2076 cd a.sh b.sh c.sh 2077 history #take 2nd arg from 2076th command history $ ls !2076:2 ls b.sh b.sh |
ls /tmp cd !* #you are now in /tmp |
Delete last 10 commands from history
You can edit vi $HISTFILE
file or use snippet below. It also delete the snippet execution entry.
pos=$HISTCMD; start=$(( $pos-11 )); end=$(( $pos-1 )); for i in $(eval echo "{${start}..${end}}"); do history -d $start; done
It uses $HISTCMD environment var to get the history index and uses that to delete last 10 entries in history.
Delete history range
If you delete line N from the history, then line N+1 moves in position N etc. Therefore for loop has reverse sequence from latest history to older, eg. range from, 6263 to 5845 history lines.
for i in {6263..5845}; do history -d $i; done
Persistent history
To persist your history and write every command to the file add below do the end of your .bashrc
If you are Ubuntu user comment out these 2
# HISTSIZE=1000 # HISTFILESIZE=2000
Add at the end of your .bashrc
# Eternal bash history. # --------------------- export HISTFILESIZE=10000 export HISTSIZE=10000 export HISTTIMEFORMAT="[%F %T] " export HISTFILE=~/.bash_eternal_history # Force prompt to write history after every command. PROMPT_COMMAND="history -a; $PROMPT_COMMAND"
Copy current history to new history file
$ cat ~/.bash_history >>~/.bash_eternal_history
Resources
- CustomizingBashPrompt Ubuntu wiki
- Git Bash Prompt repo project Great informative Git prompt
- History-Interaction Bash GNU manual