How to customize bash
InstallFest 2017

Lukáš Bařinka

Ways of customization

Invocation and Configuration Files

Invocation Options

-l / --login
login shell
--noprofile
--init-file ⬚
ommit / use file
--norc
--rcfile ⬚
omit / use file
-r / --restricted
restricted shell
-v / --verbose
verbose mode
--posix
$POSIXLY_CORRECT
set -o posix
POSIX compatible mode

Logout


							cat ~/.bash_logout
							# ~/.bash_logout: executed by bash(1) when
							# login shell exits. When leaving the console
							# clear the screen to increase privacy.

							if [ "$SHLVL" = 1 ]; then
							   [ -x /usr/bin/clear_console ] &&
							      /usr/bin/clear_console -q
							fi
						

Options

  • set options
    
    									set -o
    									allexport      off
    									braceexpand    on
    									emacs          on
    
    									set +o
    									set +o allexport
    									set -o braceexpand
    									set -o emacs
    								
  • shopt options
    
    									shopt
    									autocd       off
    									cdspell      off
    									cmdhist      on
    
    									shopt -p
    									shopt -u autocd
    									shopt -u cdspell
    									shopt -s cmdhist
    								

Set Options 1

  • -a / -o allexport
    
    									foo=bar
    									declare -p foo
    									declare -x foo="bar"/tmp
    								
  • -b / -o notify
    
    									sleep 1000 &
    									[1] 20107
    									kill %1
    									[1]+  Terminated      sleep 1000
    								

Set Options 2

  • -e / -o errexit
    
    									foo
    									[shell exits]      
    								
  • -r / -o noglob
    
    									echo /*
    									/*
    								
  • -k / -o keyword
    
    									a=1 bash -c 'declare -p a b' b=2
    									declare -x a="1"
    									declare -x b="2"
    								

Set Options 3

  • -B / -o braceexpand
    
    									echo {01..20..2}
    									01 03 05 07 09 11 13 15 17 19
    								
  • -H / -o histexpand
    
    									!!
    									echo {01..20..2}
    									01 03 05 07 09 11 13 15 17 19
    								

Set Options 4

  • -C / -o noclobber
    
    									> foo
    									> foo
    									bash: foo: cannot overwrite existing file
    								
  • -o ignoreeof
    
    									IGNOREEOF=2
    									Ctrl + d
    									Use "exit" to leave the shell.
    									Use "exit" to leave the shell.
    								

Set Options 5

  • -u / -o nounset
    
    									: $a $b $c; foo
    									bash: a: unbound variable
    								
  • -t / -o onecmd
    
    									pwd; sleep 5
    									/tmp
    									[shell exits after 5 seconds]
    								

Set Options 6

  • -P / -o physical
    
    									ln -s ~ /tmp/h
    									cd /tmp/h/.. ; pwd
    									/home
    								
  • -o pipefail
    
    									grep :/var/ruuun/ /etc/passwd | wc -l
    									0
    									echo $?
    									1
    								

Set Options 7

  • -x / -o xtrace
    
    									echo $(( $(echo $(( $(date +%s) + 3600)) \
    									         | wc -c ) - 1))
    									++ wc -c
    									+++ date +%s
    									++ echo 1488498282
    									+ echo 10
    									10
    								
  • -o vim / -o emacs

Shell Options 1

  • autocd
    
    									/tmp
    									cd -- /tmp
    								
  • cdable_vars
    
    									foo=/var/tmp
    									cd foo
    									/var/tmp
    								
  • cdspell
    
    									cd /tpm
    									/tmp
    								
  • checkjobs
    
    									sleep 100 &
    									[1] 27819
    									exit
    									There are running jobs.
    									[1]+  Running   sleep 100 &
    								

Shell Options 2

  • cmdhist — bash attempts to save all lines of a multiple-line command in the same history entry
    
    									while sleep 1; do
    									   date
    									done
    									while sleep 1; do date; done
    								
  • direxpand
    
    									foo=/var/tmp
    									ls $foo tab ls /var/tmp
    								

Shell Options 3

  • dirspell
    
    									cd /tpm/ tab cd /tmp/
    								
  • dotglob
    
    									echo *
    									.aptitude .bash_history .bash_logout
    									.bashrc .blender ...
    								
  • expand_aliases

Shell Options 4

  • extglob
    
    									rm img+([0-9]).jpg
    									rm img!(+([0-9]).jpg
    									rm img*.@(jpg|png|gif)
    								
  • failglob
    
    									echo fi*le
    									bash: no match: fi*le
    								

Shell Options 5

  • force_fignore — suffixes specified by the $FIGNORE cause words to be ignored
  • 
    									FIGNORE=.swp:.tmp:~
    									ls tab
    								
  • globasciiranges
    
    									touch {a..z} {A..Z}
    									echo [a-z]
    									a b c d ...
    								

Shell Options 6

  • globstar
    
    									mkdir -p /var/tmp/a/b/c
    									file /var/tmp/a/**
    									/var/tmp/a/:    directory
    									/var/tmp/a/b:   directory
    									/var/tmp/a/b/c: directory
    								

Shell Options 7

  • histappend — history list is appended to the file, rather than overwriting the file
  • histverify — resulting line is loaded into the readline editing buffer, allowing further modification
  • lithist — multi-line commands are saved to the history with embedded newlines rather than using semicolons

Shell Options 8

  • nocaseglob
    
    									echo .v*
    									.vim .viminfo .viminfz.tmp .vimrc .VirtualBox
    								
  • nullglob
    
    									mkdir tmp
    									echo tmp/*
    								

Shell Options 9

  • progcomp — programmable completion facilities are enabled
  • xpg_echo
    
    									echo 'a\nb'
    									a
    									b
    								

Variables

var=val
var+=ue
variable assignment
array=(item1 item2)
array+=(item3)
array assignment
unset var
remove variable/function
set
list all variables/functions
env
list environment
declare -p var
list specific variable
export var
export to envirnonment

Shell Variables 1

  • $BASH_CMDS[] (unsetting element has no effect)
    
    									BASH_CMDS+=([d]=/usr/bin/date)
    									BASH_CMDS[grep]=/usr/xpg4/bin/grep
    									hash
    									hits    command
    									2       /usr/xpg4/bin/grep
    									0       /usr/bin/date
    									1       /usr/bin/man
    								

Shell Variables 2

  • $BASH_XTRACEFD
    
    									exec 3>/dev/pts/4
    									BASH_XTRACEFD=3
    									set -x
    								
  • $CDPATH
    
    									CDPATH=~/Project:/var/www/vhosts
    									cd if17
    									/home/barinkl/Project/if17
    								

Shell Variables 3

  • $EXECIGNORE — (patterns) ignored by command search (completion), except in hash table
    
    									EXECIGNORE=*/bz*:*grep*
    								
  • $FCEDIT
    
    									FCEDIT=vim
    									fc
    								

Shell Variables 4

  • $FIGNORE — suffices ignored by filename completion
    
    									FIGNORE='~:.bak:.tmp'
    								
  • $GLOBIGNORE — suffices ignored by globbing
    
    									GLOBIGNORE=*.bak:*.tmp
    								

Shell Variables 5

  • $HISTCONTROL — second and subsequent lines of a multi-line compound command are not tested
    
    									HISTCONTROL=ignorespace:ignoredups:erasedups
    								
  • $HISTFILE, $HISTFILESIZE, $HISTSIZE
    
    									# /dev/null disables saving history
    									HISTFILE=~/.bash_history
    									HISTSIZE=500
    									HISTFILESIZE=$HISTSIZE
    								

Shell Variables 6

  • $HISTIGNORE — (patterns) ignored by history
    (& = suppresses duplicate entries)
    
    									HISTIGNORE="&:ls:[bf]g:exit:[ \t]*"
    								
  • $HISTTIMEFORMAT — adds #TIMESTAMP into history file
    
    									HISTTIMEFORMAT='%Y-%m-%d %T'
    								

Shell Variables 7

  • $IFS — (patterns) ignored by history
    (& = suppresses duplicate entries)
    
    									IFS=:
    									while read user:pass:uid:gid:comm:home:shell
    									do ...
    									done < /etc/passwd
    									IFS=$' \t\n'
    								
  • $TMOUT — timeout for read, select and shell

Shell Variables 8

  • $LANG, $LC_*
    • sorting the results of pathname expansion
    • range expressions
    • character classes
    • equivalence classes
    • collating sequences
    • number formatting
    • data and time formatting

							touch {a..z} {A..Z} é ch
							export LC_ALL=en_US.utf8
							ls [a-z]* | tr -d '\n'
							aAbBcCchdDeEéfFg...yYz

							export LC_ALL=C
							ls [a-z]* | tr -d '\n'
							abcchdefghijklmnopqrstuvwxyz

							export LC_COLLATE=cs_CZ.utf8 LC_CTYPE=cs_CZ.utf8
							ls [[:lower:]]* | tr -d '\n'
							abcdeéfghchijklmnopqrstuvwxyz
						

Shell Variables 9

  • $PS0 — after reading a command and before the command is executed
    
    									PS0='\e[01;40;33m\
    									$(printf "%${COLUMNS}s" \!)\e[0m\n'
    								
  • $PS1 — primary prompt
  • $PS2 — secondary prompt
  • $PS3 — prompt for the select command
  • $PS4 — before each command during an execution trace

Shell Variables 10

  • $PROMPT_COMMAND — value is executed as a command prior to issuing each primary prompt
    
    									export PROMPT_COMMAND='history -a; history -n'
    									PS1='\[\033]0;\u@\h:\w\007\]\u@\h:\w\$ '
    								
  • $PROMPT_DIRTRIM — number of trailing directory components to retain when expanding the \w and \W string escapes
    
    									PROMPT_DIRTRIM=1; cd /var/log/apache2
    									user@host:.../apache2 >
    								

Aliases

shopt -s expand_aliases
enable alias expansion
alias d=date
unalias d
add / remove alias
alias
list aliases
$BASH_ALIASES[]
array of aliases (writeable)
  • $BASH_ALIASES[]
    
    									BASH_ALIASES+=([sl]=ls [..]='cd ..')
    								

							alias c='cd '
							alias p='~/Documents/Work/Projects'
							c p
							cd ~/Documents/Work/Projects
						

For almost every purpose,
aliases are superseded by shell functions.

Functions

function d() { date; }
declaration of function
declare -F / -f
list of functions / with code
export -f func
export function to subshell
command_not_found_handle
invoked with the original command and arguments

							function command_not_found_handle {
							if [ -x /usr/lib/command-not-found ]
							then
							   /usr/lib/command-not-found -- "$1"
							   return $?
							elif [ -x /usr/share/command-not-found/command-not-found ]
							then
							   /usr/share/command-not-found/command-not-found -- "$1"
							   return $?
							else
							   printf "%s: command not found\n" "$1" >&2
							   return 127
							fi
							}
						

builtin / command

  • builtin
    
    									function cd {
    									   echo "From: $PWD" >&2
    									   builtin cd "$@"
    									   echo "To: $PWD" >&2
    									}
    								

builtin / command

  • builtin
    
    									function du {
    									   command du -sh "$@" \
    									   | egrep '^([0-9.]+G|([5]|1[0-9])[0-9][0-9]M)'
    									}
    								

Traps

trap date INT
declaration of trap (for ^C)
stty stop : ; stty start ,
set characters to send SIGSTOP/SIGSTART
stty -ixon
ignore SIGSTART/SIGSTOP
disown -a
remove all jobs from current shell

stty — Set Teletype


							stty -a | sed -n 2,4p
							intr = ^C; quit = ^\; erase = ^?; kill = ^U;
							   eof = ^D; eol = <undef>;
							eol2 = <undef>; swtch = <undef>; start = ^Q;
							   stop = ^S; susp = ^Z; rprnt = ^R;
							werase = ^W; lnext = ^V; discard = ^O; ...
							stty intr ^T
						

Disown shell job


							xclock &
							[1] 21157
							jobs
							[1]+  Running                 xclock &
							disown %1
							jobs

						

PS0 and Trap on DEBUG


							trap 'echo DEBUG' DEBUG
							PS0=$'PS0\n'
							pwd; echo .
							PS0
							DEBUG
							/home/barinkl
							DEBUG
							.
							DEBUG
						

Readline

--noediting
disable readline library
~/.inputrc or $INPUTRC
readline (default) startup file
bind
bind -x
bind text / command to keys
bind -p
list bindings

Bind Keys to Actions


							showkey -a   F2
							Press any keys - Ctrl-D will terminate this ...

							^[OQ   27 0033 0x1b
							       79 0117 0x4f
							       81 0121 0x51

							Ctrl+V  F2
							^[OQ

							bind "\"\eOQ\":\"git commit -am ''\e[D\""
							bind -x '"\ez":"date"'
						

Readline Configuration


							
							set blink-matching-paren on
							set expand-tilde on
							set keyseq-timeout 500
							"\C-t": forward-search-history
							"##":   insert-comment
							"\C-o": "> /dev/null"
							"\ez":  "date\n"
							"\eOQ": "git commit -am ''\e[D" 
							
						

Enable Built-in Command

enable -f /usr/lib/bash/fifno finfo
enable new built-in command finfo
enable -d finfo
disable new built-in command finfo

finfo vs stat


							time for ((i=0;i<1000;i++))
							do
							   finfo -m .           stat -c %Y .
							done >/dev/null

							   real  0m0,005s       real  0m0,768s
							   user  0m0,004s       user  0m0,020s
							   sys   0m0,000s       sys   0m0,164s
						

shared objects

finfo
display information about file attributes
realpath
display pathname in canonical form
strftime
display formatted time

Process limits

umask # 0022
umask -S # u=rwx,g=rx,o=rx
umask -p # umask 0022
umask 27
display or set file mode mask
ulimit -a
ulimit -u 100
display or modify shell resource limits

External tools settings

ls --color
colorize output of ls (=always|auto|never)
grep --color
colorize output of grep (=always|auto|never)
$LS_COLORS / $GREP_COLORS
eval "$(dircolors)"
setup of colors for ls/grep command
less -R / --raw-control-chars
display "raw" characters (e.g. ls --color=always | less -R)

^D

?