[[unix]] [[cli]] [[shell]] # Bash ## Reference - [Bash-Oneliners](https://github.com/onceupon/Bash-Oneliner) - [Bash conditional expressions](https://www.gnu.org/software/bash/manual/html_node/Bash-Conditional-Expressions.html) - [Pattern Matching](https://www.gnu.org/software/bash/manual/html_node/Pattern-Matching.html) - [Shell Parameter Expansion](https://www.gnu.org/software/bash/manual/html_node/Shell-Parameter-Expansion.html) - [Shell Tools and Scripting (MIT missing-semester)](https://missing.csail.mit.edu/2020/shell-tools/) - [pure sh bible](https://github.com/dylanaraps/pure-sh-bible) - [shellcheck](https://www.shellcheck.net/) - bash linter ### Special Vars | | | | ---------------- | ------------------------------------------------------------------------------------------------------ | | `$0` | name of the shell or shell script | | `$1`, `$2`, `$3` | [positional parameters](https://www.gnu.org/software/bash/manual/html_node/Positional-Parameters.html) | | `"$@"`  | an array-like representation of positional parameters: `{$1, $2, $3 ...}` | | `"$*"` | the IFS expansion of positional parameters, `$1 $2 $3 ...` | | `$#`  | count of positional parameters | | `$-`  | current shell options | | `$_`  | most recent parameter | | `$IFS` | (input) field separator | | `$` | current shell PID (not sub-shell) | | `$?`  | most recent pipeline exit status | | `$!`  | most recent background PID | | | | - [special parameters](https://www.gnu.org/software/bash/manual/html_node/Special-Parameters.html) - [shell variables](https://www.gnu.org/software/bash/manual/html_node/Shell-Variables.html) ### Config Files | file | order | use | execution | notes | | ----------------- | ----- | ---------------------------- | ----------------------------------- | ---------------------------------------------------------------------------------- | | `/etc/profile` | 0 | login shell | if exists | | | `~/.bash_profile` | 1 | login shell | if exists, skips other config files | commands that should execute 1x, conditionally sources `~/.profile` or `~/.bashrc` | | `~/.bash_login` | 2 | login shell | if exists, skips other config files | | | `~/.profile` | 3 | login shell | if exists | | | `~/.bashrc` | | interactive, non-login shell | | executed on every shell launch | #### Managing `dotfiles` - <https://dotfiles.github.io> ##### With [just a git alias](https://fwuensche.medium.com/how-to-manage-your-dotfiles-with-git-f7aeed8adf8b) ```bash git init --bare $HOME/.dotfiles # put this in .bashrc alias dotfiles='/usr/bin/git --git-dir=$HOME/.dotfiles/ --work-tree=$HOME' # tell git to hide untracked files dotfiles config --local status.showUntrackedFiles no dotfiles status dotfiles add .vimrc dotfiles commit -m "Add vimrc" dotfiles add .bashrc dotfiles commit -m "Add bashrc" dotfiles push ``` ##### With [chezmoi](https://dev.to/jerrynsh/a-brief-guide-to-manage-dotfiles-1h59) /ʃeɪ mwa/ (shay-moi) - [user guide](https://www.chezmoi.io/user-guide/command-overview/) - <https://github.com/pmbauer/dotfiles> ```bash # pull changes and apply in a single command chezmoi update # pull changes and see what would change chezmoi git pull -- --rebase && chezmoi diff # apply changes in ~/.local/share/chezmoi chezmoi apply # install on new machine with single command # note: setup ssh keys first if your dotfiles repo is private # note: populate ~/.config/chezmoi/chezmoi.toml first for templates $ sh -c "$(curl -fsLS https://chezmoi.io/get)" -- init --apply $GITHUB_USERNAME ``` ## Cookbook ### strict mode ```bash #!/usr/bin/env bash set -euo pipefail IFS=\n\t' ``` ### ssh wrapper template ```bash #!/usr/bin/env bash while getopts "1246ab:c:e:fgi:kl:m:no:p:qstvxAB:CD:E:F:GI:J:KL:MNO:PQ:R:S:TVw:W:XYy" opt; do args="${args:-} -${opt} ${OPTARG:-}" done shift $((OPTIND -1)) ssh ${args:-} "${@}" ``` ### 2-way proxy socket ```bash mkfifo /tmp/fifo ncat -l -k -U /tmp/test.sock 0</tmp/fifo | ncat 127.0.0.1 8126 1>/tmp/fifo # socat proxy tcp # proxy port target socat TCP-LISTEN:8080,fork,reuseaddr TCP:google.com:443 ``` ### Epoch conversion and [[time]] ```bash # from epoch seconds date -d@1718219864 # epoch seconds date +%s # epoch nanoseconds date +%s%N # human language epoch seconds date +%s -d "1 day ago" # epoch milliseconds ## truncate ns to 3 most significant digits date +%s%3N ## ignore all but the ms portion date +%s%N | cut -b1-13 ## bash math echo $(($(date +%s%N)/1000000)) ``` ### Random Numbers ```bash # random number in [15, 20) echo $(($(($RANDOM % 5))+15)) # random number in [15,20) using shuf # more portable for shells that don't support $RANDOM shuf -i15-19 -n1 ```