From 50e07a8bca68d2f568df44166fa94383141c2696 Mon Sep 17 00:00:00 2001 From: Johannes Stoelp Date: Wed, 1 May 2024 14:47:26 +0200 Subject: shells: move shells into own group --- src/shells/README.md | 5 + src/shells/bash.md | 259 +++++++++++++++++++++++++++++++++++ src/shells/fish.md | 280 ++++++++++++++++++++++++++++++++++++++ src/shells/zsh.md | 371 +++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 915 insertions(+) create mode 100644 src/shells/README.md create mode 100644 src/shells/bash.md create mode 100644 src/shells/fish.md create mode 100644 src/shells/zsh.md (limited to 'src/shells') diff --git a/src/shells/README.md b/src/shells/README.md new file mode 100644 index 0000000..3a7c121 --- /dev/null +++ b/src/shells/README.md @@ -0,0 +1,5 @@ +# Shells + +- [zsh](./zsh.md) +- [bash](./bash.md) +- [fish](./fish.md) diff --git a/src/shells/bash.md b/src/shells/bash.md new file mode 100644 index 0000000..f27b3a2 --- /dev/null +++ b/src/shells/bash.md @@ -0,0 +1,259 @@ +# bash(1) + +## Expansion + +### Generator + +```bash +# generate sequence from n to m +{n..m} +# generate sequence from n to m step by s +{n..m..s} + +# expand cartesian product +{a,b}{c,d} +``` + +### Parameter +```bash +# default value +bar=${foo:-some_val} # if $foo set, then bar=$foo else bar=some_val + +# alternate value +bar=${foo:+bla $foo} # if $foo set, then bar="bla $foo" else bar="" + +# check param set +bar=${foo:?msg} # if $foo set, then bar=$foo else exit and print msg + +# indirect +FOO=foo +BAR=FOO +bar=${!BAR} # deref value of BAR -> bar=$FOO + +# prefix +${foo#prefix} # remove prefix when expanding $foo +# suffix +${foo%suffix} # remove suffix when expanding $foo + +# substitute +${foo/pattern/string} # replace pattern with string when expanding foo +# pattern starts with +# '/' replace all occurences of pattern +# '#' pattern match at beginning +# '%' pattern match at end + +# set programmatically with priintf builtin +printf -v "VAR1" "abc" +NAME=VAR2 +printf -v "$NAME" "%s" "def" +``` + +> Note: `prefix`/`suffix`/`pattern` are expanded as [pathnames](#pathname). + +### Pathname + +```bash +* match any string +? match any single char +\\ match backslash +[abc] match any char of 'a' 'b' 'c' +[a-z] match any char between 'a' - 'z' +[^ab] negate, match all not 'a' 'b' +[:class:] match any char in class, available: + alnum,alpha,ascii,blank,cntrl,digit,graph,lower, + print,punct,space,upper,word,xdigit +``` + +With `extglob` shell option enabled it is possible to have more powerful +patterns. In the following `pattern-list` is one ore more patterns separated +by `|` char. + +```bash +?(pattern-list) matches zero or one occurrence of the given patterns +*(pattern-list) matches zero or more occurrences of the given patterns ++(pattern-list) matches one or more occurrences of the given patterns +@(pattern-list) matches one of the given patterns +!(pattern-list) matches anything except one of the given patterns +``` +> Note: `shopt -s extglob`/`shopt -u extglob` to enable/disable `extglob` +> option. + +## I/O redirection + +> Note: The trick with bash I/O redirection is to interpret from left-to-right. + +```bash +# stdout & stderr to file +command >file 2>&1 +# equivalent +command &>file + +# stderr to stdout & stdout to file +command 2>&1 >file +``` +> The article [Bash One-Liners Explained, Part III: All about +> redirections](https://catonmat.net/bash-one-liners-explained-part-three) +> contains some nice visualization to explain bash redirections. + +### Explanation + +```bash +j>&i +``` +Duplicate `fd i` to `fd j`, making `j` a copy of `i`. See [dup2(2)][dup2]. + +Example: +```bash +command 2>&1 >file +``` +1. duplicate `fd 1` to `fd 2`, effectively redirecting `stderr` to `stdout` +2. redirect `stdout` to `file` + +## Process substitution ([ref][psub]) + +Process substitution allows to redirect the stdout of multiple processes at +once. +```bash +vim -d <(grep foo bar) <(grep foo moose) +``` + +## Command grouping + +Execute commands in a group with or without subshell. Can be used to easily +redirect stdout/stderr of all commands in the group into one file. +```bash +# Group commands without subshell. +v=abc ; { v=foo; echo $v; } ; echo $v +# foo +# foo + +# Group commands with subshell. +v=abc ; ( v=foo; echo $v; ) ; echo $v +# foo +# abc +``` + +## Argument parsing with `getopts` + +The `getopts` builtin uses following global variables: +- `OPTARG`, value of last option argument +- `OPTIND`, index of the next argument to process (user must reset) +- `OPTERR`, display errors if set to `1` + +```bash +getopts [] +``` +- `` specifies the names of supported options, eg `f:c` + - `f:` means `-f` option with an argument + - `c` means `-c` option without an argument +- `` specifies a variable name which `getopts` fills with the last parsed option argument +- `` optionally specify argument string to parse, by default `getopts` parses `$@` + +### Example +```bash +#!/bin/bash +function parse_args() { + while getopts "f:c" PARAM; do + case $PARAM in + f) echo "GOT -f $OPTARG";; + c) echo "GOT -c";; + *) echo "ERR: print usage"; exit 1;; + esac + done + # users responsibility to reset OPTIND + OPTIND=1 +} + +parse_args -f xxx -c +parse_args -f yyy +``` + +## Regular Expressions + +Bash supports regular expression matching with the binary operator `=~`. +The match results can be accessed via the `$BASH_REMATCH` variable: +- `${BASH_REMATCH[0]}` contains the full match +- `${BASH_REMATCH[1]}` contains match of the first capture group + +```bash +INPUT='title foo : 1234' +REGEX='^title (.+) : ([0-9]+)$' +if [[ $INPUT =~ $REGEX ]]; then + echo "${BASH_REMATCH[0]}" # title foo : 1234 + echo "${BASH_REMATCH[1]}" # foo + echo "${BASH_REMATCH[2]}" # 1234 +fi +``` +> **Caution**: When specifying a `regex` in the `[[ ]]` block directly, quotes will be treated as part of the pattern. +> `[[ $INPUT =~ "foo" ]]` will match against `"foo"` not `foo`! + +## Completion + +The `complete` builtin is used to interact with the completion system. +```bash +complete # print currently installed completion handler +complete -F # install as completion handler for +complete -r # uninstall completion handler for +``` + +Variables available in completion functions: +```bash +# in +$1 # +$2 # current word +$3 # privous word + +COMP_WORDS # array with current command line words +COMP_CWORD # index into COMP_WORDS with current cursor position + +# out +COMPREPLY # array with possible completions +``` + +The `compgen` builtin is used to generate possible matches by comparing `word` +against words generated by `option`. +```bash +compgen