My Dotfiles 2021
This is a walkthrough of my dotfiles repository.
This is mostly intended as a reference post I can use to point people to when they ask how I do a specific thing, but you might be able to find some fun little tweaks you didn’t know about.
A lot has happened since I started the repository to keep track of my dotfiles across machines in 2014. These days I’m using them mostly on MacOS, but I do have a small XPS 15 running Arch Linux that also see a bit of use.
We are skipping my tmux configuration as that is probably a post in itself.
§psqlrc
I have a custom psqlrc
file that for when I use the psql
tool.
1\set QUIET 1
2\pset null '¤' -- Show NULL values as the ¤ character. Much easier to spot.
3\pset linestyle unicode -- Nicer borders
4\pset border 2 -- show table frame border
5
6-- Prompt line itself, like Bash's PS1 and PS2
7\set PROMPT1 '%[%033[1m%][%n@%/] %R%# '
8-- SELECT * FROM<enter>. %R shows what type of input it expects.
9\set PROMPT2 '... %R %# '
10
11-- Always time things
12\timing
13
14-- Expanded table formatting mode = auto
15\x auto
16
17-- On error, don't auto-rollback when in interactive mode
18\set ON_ERROR_ROLLBACK interactive
19
20-- Be verbose
21\set VERBOSITY verbose
22
23-- Histfile seperate per database
24\set HISTFILE ~/.psql_history- :DBNAME
25\set HISTCONTROL ignoredups
26
27-- auto-completed keywords will be uppercased
28\set COMP_KEYWORD_CASE upper
29\unset QUIET
§Bash
The meat of my dotfiles is the bashrc
, which configures my bash that I use
every day.
I’ve tweaked this system over the last 5 years and this is where I’m at today.
Most of these I’ve probably grabbed from someone elses system and tweaked them as needed.
§Architecture
The bashrc
file is designed to be either symlinked into place or sourced
from your own bashrc script.
On my current workstation I source it from ~/.bashrc
to mix it with some local configuration.
The bashrc
file sets up the library that I use to work with my dotfiles,
and the rest of the configuration is stored in a bashrc.d/
directory next to the
bashrc
script.
The library consists of 4 bash functions:
dotfiles_directory
dotfiles_platform
dotfiles_match
dotfiles_source
dotfiles_directory
outputs the directory that the bashrc
file is located in.
This works across symlinks, which is why it is a bit complicated.
dotfiles_platform
outputs the current “platform” as a normalized string.
I use this for configuration that is only relevant on certain platforms.
dotfiles_match
outputs all configuration files that matches a pattern,
or every relevant file if not pattern is given.
It uses filenames from the configuration directory to check this.
Valid filenames match <name>.<platform | all>.sh
.
The files are returned in sorted order by name.
dotfiles_source
Takes an optional pattern just line the above function, and sources files that match. If the debug environment variable DOTFILES_DEBUG
is set to true then it will do so while timing the source.
If a source command fails it will write an error about it to STDERR.
Finally, the bashrc
file calls dotfiles_source
with no pattern,
which will source all configuration files relevant for the current platform.
§Dotfiles
If the order of sourcing is important, the files are named <nn>.<name>.<platform>.sh
which will source those files first.
Files that most be sourced last are prefixed with zz
.
I currently don’t have any of those.
§Aliases
The first file is my alias file. I don’t tend to use aliases a lot but I have a few:
1if command -v nvim >/dev/null; then
2 alias vim=nvim
3fi
4if command -v pgcli >/dev/null; then
5 alias pg=pgcli
6fi
7
8alias v=vim # I'm really lazy
9alias week="date +%GW%V" # e.g. 2020W42
10alias cal="cal -Nw3sDK" # I prefer this
The command -v pgcli >/dev/null;
checks if pgcli
exists.
I’m doing this a lot in my dotfiles to only perform configuration if some
command is available on $PATH
.
§Path
I’ve tinkered with PATH
so much that I’ve made a simply utility to work with them.
The file 00.path.all.sh
defines two helper functions that the rest of the
configuration will use to work with PATH
:
1path_prepend () {
2 if ! [[ "$PATH" = *"$1"* ]]; then
3 export PATH="$1:$PATH"
4 fi
5 return 0
6}
7path_append () {
8 if ! [[ "$PATH" = *"$1"* ]]; then
9 export PATH="$PATH:$1"
10 fi
11 return 0
12}
It also defines my python paths. I should have moved these to my python config but I haven’t yet :)
1if command -v python3 >/dev/null; then
2 path_append "$(python3 -c 'import site;print(site.USER_BASE)')/bin"
3fi
4if command -v python2 >/dev/null; then
5 path_append "$(python2 -c 'import site;print(site.USER_BASE)')/bin"
6fi
I normally use a single python2 and python3 on my system so this works fine.
I also have a Darwin specific path configuration at 01.path.darwin.sh
.
This is our first platform specific file:
1if [ -x /usr/libexec/path_helper ]; then
2 eval `/usr/libexec/path_helper -s`
3fi
4if [[ -d /usr/local/opt/coreutils/libexec/gnubin ]]; then
5 path_prepend "/usr/local/opt/coreutils/libexec/gnubin"
6fi
7if [[ -d /usr/local/opt/coreutils/libexec/gnuman ]]; then
8 export MANPATH="/usr/local/opt/coreutils/libexec/gnuman:$MANPATH"
9fi
I have Coreutils installed through brew, and this handles the path and manual paths for me.
§Private Configuration
On most platforms I have secret configuration (passwords, tokens and such) that
I don’t want to commit to my public dotfile repo.
I’ve made a habbit of placing such secrets in a ~/.bash_private
file,
and have a dotfile 02.private.all.sh
that simply source that if it exists:
§HOME paths
Because different tools can’t agree on where to put there executables in my home folder, I have this catch-all kind of “just prepend bin/ to PATH please”
1if [[ -d $HOME/bin/ ]]; then
2 path_prepend "$HOME/bin"
3fi
4if [[ -d $HOME/.bin/ ]]; then
5 path_prepend "$HOME/.bin"
6fi
7if [[ -d $HOME/.local/bin/ ]]; then
8 path_prepend "$HOME/.local/bin"
9fi
§Sublime Text on MacOS
If sublime is installed, add it’s bin/
to the path.
1if [ -d "/Applications/Sublime Text.app/Contents/SharedSupport/bin" ]; then
2 path_append "/Applications/Sublime Text.app/Contents/SharedSupport/bin"
3fi
§asdf version manager
I use asdf for a lot of my tool version management.
Currently I use it for erlang
, elixir
, nodejs
, ruby
.
The dotfile itself is simple: the tool itself and bash completions for it:
§AWS CLI
This enables bash completions for the aws
CLI.
§Bash Completion
This sources the bash-completion project if it is installed.
Note that brew installs these in it’s prefix, so this won’t work if you’ve installed it via brew. I have a section further down for that.
1if [ -f /usr/share/bash-completion/bash_completion ]; then
2 . /usr/share/bash-completion/bash_completion
3fi
§Docker Completion
This enables bash completion for the docker command when installed via the Docker for Mac project.
1if [ -f /Applications/Docker.app/Contents/Resources/etc/docker.bash-completion ]; then
2 . /Applications/Docker.app/Contents/Resources/etc/docker.bash-completion
3fi
§EDITOR environment variable
This sets up the EDITOR
environment variable such that if the
subl
command exists, we’ll use that, otherwise if vim
exists, we’ll use that.
I love Sublime Text and it has been my primary editor for most of my professional career, but in a pinch I’m fine with vim as well.
1if command -v subl >/dev/null; then
2 export EDITOR="subl --wait"
3elif command -v vim >/dev/null; then
4 export EDITOR="vim"
5fi
§Erlang and Elixir
Some versions of erlang requires a kernel flag to be set to enable the shell
history. This is an absolute pain to remember but luckily you can set those
in an environment variable as well, so this does that.
It also adds the ~/.mix/escripts
path to my PATH
1if command -v erl >/dev/null || command -v iex >/dev/null; then
2 export ERL_AFLAGS="-kernel shell_history enabled"
3 ESCRIPTS_PATH="/Users/tbug/.mix/escripts"
4 if [[ -d "$ESCRIPTS_PATH" ]]; then
5 path_append "$ESCRIPTS_PATH"
6 fi
7fi
§Grep Aliases
I want my grep in color.
1if command -v grep >/dev/null; then
2 alias grep='grep --color=auto'
3 alias fgrep='fgrep --color=auto'
4 alias egrep='egrep --color=auto'
5fi
§Homebrew Bash Completions
This handles the bash completion project installed via brew.
1if command -v brew > /dev/null && [ -f $(brew --prefix)/etc/bash_completion ]; then
2 . $(brew --prefix)/etc/bash_completion
3elif command -v brew > /dev/null && [ -f $(brew --prefix)/share/bash-completion/bash_completion ]; then
4 . $(brew --prefix)/share/bash-completion/bash_completion
5fi
§Fake a slow network with ipfw
It’s been years since I’ve used this, but I remember it being really useful.
1if command -v ipfw >/dev/null; then
2 #fake slow network
3 alias slowNetwork='sudo ipfw pipe 1 config bw 350kbit/s plr 0.05 delay 500ms && sudo ipfw add pipe 1 dst-port http'
4 alias flushNetwork='sudo ipfw flush'
5fi
§kubectl
My kubectl dotfile configuration is a bit complicated:
1if command -v kubectl >/dev/null; then
2 function k {
3 local BLUE='\033[0;34m'
4 local BOLD="\033[1m"
5 local CLEAR='\033[0m'
6 local context="$(awk '/^current-context:/{print $2}' $HOME/.kube/config)"
7 printf "${BLUE}${BOLD}$context${CLEAR}\n" >&2
8 kubectl "$@"
9 }
10 if [[ -d $HOME/.kube ]] && [[ ! -f $HOME/.kube/completion.bash.inc ]]; then
11 kubectl completion bash > $HOME/.kube/completion.bash.inc
12 fi
13 # if the kubectl completion is not loaded, load it:
14 if ! command -v __start_kubectl >/dev/null; then
15 source $HOME/.kube/completion.bash.inc
16 fi
17 # make kubectl completions work for our short-name function `k` as well
18 if command -v __start_kubectl >/dev/null; then
19 complete -o default -F __start_kubectl k
20 fi
21 if command -v kubectx >/dev/null; then
22 alias kx="kubectx"
23 _kx_contexts () {
24 local curr_arg;
25 curr_arg=${COMP_WORDS[COMP_CWORD]};
26 COMPREPLY=($(compgen -W "- $(kubectl config get-contexts --output='name')" -- $curr_arg ))
27 }
28 complete -o default -F _kx_contexts kx
29 fi
30
31 # if krew plugin exists, add it to bin path
32 if [[ -d "${HOME}/.krew" ]]; then
33 path_append "${HOME}/.krew/bin"
34 fi
35
36 # if helm exists
37 if command -v helm >/dev/null; then
38 if [[ -d $HOME/.kube ]] && [[ ! -f $HOME/.kube/helm-completion.bash.inc ]]; then
39 helm completion bash > $HOME/.kube/helm-completion.bash.inc
40 fi
41 if ! command -v __start_helm >/dev/null; then
42 source $HOME/.kube/helm-completion.bash.inc
43 fi
44 fi
45fi
First, I have a bash function k
that wraps kubectl
.
It’s purpose is both as an alias so that I can just type k
for kubectl
,
but it also prints what context I’m currently using so I might notice that I’m running
something in the wrong environment.
There is also some bash completions in there, both for kubectl
itself,
but also for the k
function so I get completions for that as well.
Then I have a kubectx
alias kx
and a completion for it as well.
Then a bit for putting krew
’s bin/
onto the PATH.
And finally some helm
stuff that handles loading bash completions
for helm
.
§Manual pages
Adding some color to my man
pages.
1# colorized man pages
2man() {
3 env \
4 LESS_TERMCAP_md=$'\e[1;36m' \
5 LESS_TERMCAP_me=$'\e[0m' \
6 LESS_TERMCAP_se=$'\e[0m' \
7 LESS_TERMCAP_so=$'\e[1;40;92m' \
8 LESS_TERMCAP_ue=$'\e[0m' \
9 LESS_TERMCAP_us=$'\e[1;32m' \
10 man "$@"
11}
§Nix Hack
I’ve been toying a bit with Nix on-off, and I had issues with searching for packages. So I built a caching search function. Better tools exist to do this, and I don’t recommend stealing this, but for reference:
1if [[ -d $HOME/.nix-profile ]]; then
2 source $HOME/.nix-profile/etc/profile.d/nix.sh
3
4 export NIX_SEARCH_CACHE="$HOME/.cache/nix-search-cache"
5 nix-search () {
6 if ! [[ -e "$NIX_SEARCH_CACHE" ]]; then
7 echo "nix-search cache is empty, populating..." >&2
8 nix-search --update
9 fi
10 while (( "$#" )); do
11 case "$1" in
12 -h|--help)
13 echo "nix-search - cache and search in nix package names." >&2
14 echo " search is done with 'grep -i'" >&2
15 echo "usage:" >&2
16 echo " nix-search (-u|--update) updates the nix-search cache" >&2
17 echo " nix-search <grep args> searches the nix-search cache" >&2
18 return 1
19 ;;
20 -u|--update)
21 echo "nix-search updating cache..." >&2
22 nix-env -qaP '*' > "$NIX_SEARCH_CACHE"
23 local ret=$?
24 echo "packages available for searching: $(cat "$NIX_SEARCH_CACHE" | wc -l)" >&2
25 return $ret
26 ;;
27 --) # end argument parsing
28 shift
29 break
30 ;;
31 -*|--*=) # unsupported flags
32 echo "Error: Unsupported flag $1" >&2
33 return 1
34 ;;
35 *) # preserve positional arguments
36 local params="$params $1"
37 shift
38 ;;
39 esac
40 done
41 if [[ "$(stat -f %c "$NIX_SEARCH_CACHE")" -lt "$(( $(date +%s) - 86400 ))" ]]; then
42 echo "nix-search cache needs updating, run nix-search -u" >&2
43 fi
44 grep -i "$params" "$NIX_SEARCH_CACHE"
45 }
46
47fi
48
49# will make bash-completion happy when installed via nix
50export XDG_DATA_DIRS="$HOME/.nix-profile/share:${XDG_DATA_DIRS:-/usr/local/share:/usr/share}"
51
52# bash completions from nix:
53if [[ -f $HOME/.nix-profile/share/bash-completion/bash_completion ]]; then
54 source $HOME/.nix-profile/share/bash-completion/bash_completion
55fi
56
57# git bash completions from git package
58if [[ -f $HOME/.nix-profile/share/git/contrib/completion/git-completion.bash ]]; then
59 source $HOME/.nix-profile/share/git/contrib/completion/git-completion.bash
60fi
At the end there is some loading of completions when packages are installed via nix.
§NodeJS
§NVM
I don’t really use nvm anymore since I switched to asdf
, but this is a good example
of some of the lazy-loading of things I’ve done to speed up booting my bash shell:
1# care about nvm, only if .nvm folder exists
2if [[ -d "$HOME/.nvm" ]]; then
3 export NVM_DIR="$HOME/.nvm"
4 nvm () {
5 echo 'lazy loading nvm...' >&2
6 unset -f nvm
7 # this works on my arch machines with the nvm package installed
8 if [[ -f "/usr/share/nvm/init-nvm.sh" ]]; then
9 source /usr/share/nvm/init-nvm.sh
10 # this works on my mac with nvm installed through brew
11 elif [[ -f "/usr/local/opt/nvm/nvm.sh" ]]; then
12 source "/usr/local/opt/nvm/nvm.sh"
13 else
14 echo "nvm doesn't seen to be present." >&2
15 return 1
16 fi
17 nvm "$@"
18 }
19fi
This defines a function nvm
that - when invoked - will unset itself and look
for nvm
in the different places I have it across my machines and source it in.
The reason for doing this is that nvm
was painfully slow to load, and usually
I don’t need it, so paying an extra second in bash loading time is not worth it.
§OpenShift Completion
Almost same story as with NVM. I don’t use openshift anymore (I had a brief encouter at work)
What I did here is wrapping the completion in a lazy loader.
The reason is - again - that calling oc completion bash
was a bit slow and I rarely
needed it.
This might be useful to you if you want to lazy-load your own bash completions.
1if command -v oc >/dev/null; then
2 # lazy-load completions for oc
3 __fake_oc_completer () {
4 complete -r oc
5 unset -f __fake_oc_completer
6 source <(oc completion bash)
7 __start_oc "$@"
8 }
9 complete -F __fake_oc_completer oc
10fi
§Pager
This file used to be bigger, but currently it contains some pager configuration for
psql if pspg
is installed.
Side-note: if you don’t know pspg
you should give it a look.
It’s a really good pager for tabular content.
§Prompt
The file prompt.all.sh
defines my bash prompt (PS1
and friends)
Here it is in full:
1function __fix_stdout_nonblock_bug () {
2 # some tool somewhere keeps messing up my stdout.
3 # It's most likely a nodejs tool, at least I've seen nodejs do this multiple times,
4 # however something somewhere in my pipeline does it incosistently but often
5 # enough that it is so annoying that I want to make sure it doesn't happen.
6 # Hence this hack.
7 # This python snippet "fixes" the issue, unsetting NONBLOCK mode if it is already set.
8 # Might be worth compiling a tiny C program to do it but this seems Good Enough for now.
9 if command -v python >/dev/null; then
10 python -c 'import os,sys,fcntl; flags = fcntl.fcntl(sys.stdout, fcntl.F_GETFL); fcntl.fcntl(sys.stdout, fcntl.F_SETFL, flags&~os.O_NONBLOCK);'
11 else
12 return 1
13 fi
14}
15
16function __prompt_command () {
17 local LASTEXIT="$?"
18
19 # Fix a super annoying bug I keep seeing but can't figure out how to correct.
20 # some nodejs tool somewhere leaves stdout in nonblock mode which messes up
21 # other tools. So fix it ON EACH PROMPT!
22 __fix_stdout_nonblock_bug
23
24 local RESET="\[\033[0m\]" #reset
25 local BOLD="\[\033[1m\]" #bold
26 local DIM="\[\033[2m\]" #dim
27 local UNDERLINE="\[\033[4m\]" #underline
28
29 local DEFAULT="\[\033[39m\]"
30 local RED="\[\033[91m\]"
31 local GREEN="\[\033[32m\]"
32 local YELLOW="\[\033[93m\]"
33 local BLUE="\[\033[34m\]"
34 local MAGENTA="\[\033[95m\]"
35 local CYAN="\[\033[96m\]"
36 local WHITE="\[\033[97m\]"
37 local GREY="\[\033[90m\]"
38 # * == unstages
39 # + == staged changes
40 export GIT_PS1_SHOWDIRTYSTATE="1"
41 # $ next to branch named if stashed state
42 export GIT_PS1_SHOWSTASHSTATE="1"
43 # % next to branch name of untracked files
44 export GIT_PS1_SHOWUNTRACKEDFILES="1"
45 # will show state compared to upstream
46 # < you are behind upstream
47 # > you are ahead of upstream
48 # <> you have diverged from upstream
49 # = matches upstream
50 export GIT_PS1_SHOWUPSTREAM="auto"
51
52
53 local r="$RESET" # reset sequence
54 local p="$BOLD$CYAN" # primary color sequence
55 local s="$DIM$CYAN" # secondary color sequence
56 local f="$GREY" # framing color (usually grey)
57 local e="$RED" # error sequence
58
59 # exit status in dimmed parens and error color number
60 if [ $LASTEXIT != 0 ]; then
61 local status="$r$f($r$e${LASTEXIT}$r$f)$r "
62 else
63 local status="$r$f(0)$r "
64 fi
65
66 # virtualenv support
67 if [[ "$VIRTUAL_ENV" != "" ]]; then
68 local venv="$r$f(venv:$s${VIRTUAL_ENV##*/}$r$f)$r"
69 else
70 local venv=""
71 fi
72
73 if [[ "$AWS_PROFILE" != "" ]]; then
74 local awsenv="$r$f(aws:$s${AWS_PROFILE}$r$f)$r"
75 else
76 local awsenv=""
77 fi
78
79 local gitline=''
80 if type -t __git_ps1 > /dev/null; then
81 gitline="\$(__git_ps1 \" $r$f[$s%s$r$f]\")"
82 fi
83
84 local k8sline=''
85 if type -t kubectl > /dev/null; then
86 k8sline=" $r$f[$s\$(kubectl config current-context)$f]"
87 fi
88 export PS1="${r}${f}╭─(\t) \u@\h $r$p\w$r${gitline}${k8sline}$r\n${f}╰─${status}$r${s}\$${venv}${awsenv}$r$s>$r "
89 export PS2="${r} ${status}${s}\$${venv}${awsenv}>${r} "
90}
91
92if ! type -t __git_ps1 > /dev/null; then
93 if [[ -f /usr/share/git/git-prompt.sh ]]; then
94 . /usr/share/git/git-prompt.sh
95 elif [[ -f $HOME/.nix-profile/share/git/contrib/completion/git-prompt.sh ]]; then
96 . $HOME/.nix-profile/share/git/contrib/completion/git-prompt.sh
97 fi
98fi
99
100export PROMPT_COMMAND=__prompt_command # Func to gen PS1 after CMDs
This file contains all my prompt related things. Parts of this file dates all the way back to the start of this repo, 2014.
This is how it looks when rendered:
╭─(08:25:01) het@hetmbp ~/src/dotfiles [master=] [<k8s-context>]
╰─(0) $>
But in color, of course.
The prompt is a two-line prompt. The top information line shows
- the time
- current working directory
- user and host
- git branch and status if applicable
- currently selected Kubernetes context
And the second line shows
- exit status of last command
- current python virtualenv if applicable
- currently selected AWS profile if applicable
- the prompt.
I’ve used this two-line prompt format since 2018 and I’m still pretty happy with it.
§Ruby
Some Ruby hack that I don’t use anymore since switching completely to asdf for Ruby version management.
1if ! command -v asdf >/dev/null; then
2 # when asdf is installed don't do this ruby stuff because asdf will
3 # most likely be managing this.
4 if command -v ruby >/dev/null && command -v gem >/dev/null; then
5 if [[ -f /tmp/ruby_gem_home ]]; then
6 export GEM_HOME="$(cat /tmp/ruby_gem_home)"
7 else
8 # move GEM_HOME into home dir. Global install is messy.
9 export GEM_HOME="$(ruby -r rubygems -e 'puts Gem.user_dir')"
10 echo "$GEM_HOME" > /tmp/ruby_gem_home
11 fi
12 # prepend, because osx has some native ruby stuff that we cant really touch
13 path_prepend "$GEM_HOME/bin"
14 fi
15fi
This checks if ruby
and gem
is present, and if so, defines GEM_HOME
.
I also cache the GEM_HOME
because invoking Ruby to get the Gem.user_dir
is
painfully slow.
I also prepend the bin/
folder in the GEM_HOME
to PATH
so that it’s
picked first.
§Rust Cargo Path
I’ve toyed a bit with rust, and also have utilities installed
via cargo. This simply appends the global cargo bin/
to my PATH.
§Scaleway CLI Bash Completion
At work we have some infrastructure running at Scaleway. They have a decent CLI that I use, and this defines auto-completion for it.
1if command -v scw >/dev/null; then
2 _scw() {
3 _get_comp_words_by_ref -n = cword words
4 output=$(scw autocomplete complete bash -- "$COMP_LINE" "$cword" "${words[@]}")
5 COMPREPLY=($output)
6 # apply compopt option and ignore failure for older bash versions
7 [[ $COMPREPLY == *= ]] && compopt -o nospace 2> /dev/null || true
8 return
9 }
10 complete -F _scw scw
11fi
§smux: ssh + tmux
I have a dedicated bash function that I’ve named smux
for doing ssh
+tmux
.
It’s a shortcut for running ssh
and then tmux
once you get a session,
which is something I do many times in a day.
I’ve used the default session name of 0
so that if I for some reason
would ssh
in, and then run tmux attach
it would still attach to the expected session.
I also wrote a completion function for it, which will use hosts defined
in ~/.ssh/config
and hosts found in ~/.ssh/known_hosts
as completions.
1if command -v ssh >/dev/null; then
2 smux () {
3 if [[ "$#" -eq 0 ]]; then
4 echo -e "SSH to <destination> and attach to a tmux session.\nAny argument is passed to ssh.\n\nusage: smux <destination> [...ssh opts]" >&2
5 return 1
6 fi
7 ssh -t ${@} -- "tmux new-session -ADs0"
8 }
9 _smux()
10 {
11 local cur prev opts
12 COMPREPLY=()
13 cur="${COMP_WORDS[COMP_CWORD]}"
14 prev="${COMP_WORDS[COMP_CWORD-1]}"
15 opts=$(
16 awk '/^host/ && $2 !~ /\*/ {print $2}' ~/.ssh/config &&
17 awk '!/\[/{split($1, a, ",");for(i in a){print a[i]}}' ~/.ssh/known_hosts | sort -u
18 )
19 COMPREPLY=( $(compgen -W "$opts" -- ${cur}) )
20 return 0
21 }
22 complete -F _smux smux
23fi
The meat of it is the line:
1ssh -t ${@} -- "tmux new-session -ADs0"
Which will force a TTY and pass any arguments you gave smux
along to ssh
.
It will then run
1tmux new-session -ADs0
On the remote host.
The tmux flags given to new-session
are:
-A
makesnew-session
behave likeattach-session
if session-name already exists-D
-D
behaves like-d
toattach-session
-s0
specifies a session name. Here0
is given as the session name, which is also the default value.
§Final Thoughts
I’ve left out a few things that hasn’t seen use in a while and probably don’t even work today.