资源
Tips
sh/bash
-s: 类 unix 操作系统中用于运行带参数的 shell 脚本的命令。-s 选项用于指定脚本应该从标准输入而不是文件中读取其输入。
1 wget -O - https://raw.githubusercontent.com/nektos/act/master/install.sh | sh -s - -b /usr/local/bin
set
set -o errexit 或 set -e 表示如果任何命令的退出状态码非零(即命令执行失败),则立即退出脚本。这有助于在脚本中遇到错误时停止执行后续的命令。
set -o nounset 或 set -u 表示如果使用未定义的变量,则立即退出脚本。这有助于避免在脚本中使用未初始化的变量导致的错误。
set -o pipefail 表示如果管道中的任何命令失败,则整个管道的退出状态码将是失败。默认情况下,管道的退出状态码是最后一个命令的退出状态码。这有助于在管道中的任何命令失败时及时捕获错误。
set -x: 打开调试模式。在调试模式下,shell 会将执行的每个命令及其参数都打印出来,以便用户可以更好地了解脚本的执行过程和调试脚本中的错误。
log
颜色高亮输出,兼容 sh/bash.
[!TIP]
在 POSIX sh 中,可以使用 ANSI 转义序列来实现颜色高亮输出。ANSI 转义序列是一些特殊的字符序列,它们可以在输出中表示一些特殊的含义,如颜色、样式等等。具体来说,ANSI 转义序列以 \033[
开头,后面跟着一些数字和字符,用于指定要应用的颜色或样式。例如,\033[31m
表示将文本颜色设置为红色,\033[1m
表示将文本加粗等等。
links:
info
1 2 3 4 5 6 7 echo "---------------- Env echo ----------------" echo "it is $(date) " echo "current path: " "$PWD " echo "who is this: " "$(whoami) " echo "who is this : " "$USER " echo "pip3 version: " "$(pip3 --version) " echo "distribution:$(. /etc/os-release;echo $ID$VERSION_ID) "
arch
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 #!/usr/bin/env bash find_arch () { case ${ARCH:=$(uname -m)} in amd64) ARCH=amd64 SUFFIX=$(uname -s | tr '[:upper:]' '[:lower:]' )-${ARCH} ;; x86_64) ARCH=amd64 SUFFIX=$(uname -s | tr '[:upper:]' '[:lower:]' )-${ARCH} ;; arm64) ARCH=arm64 SUFFIX=-${ARCH} ;; s390x) ARCH=s390x SUFFIX=-${ARCH} ;; aarch64) ARCH=arm64 SUFFIX=-${ARCH} ;; arm*) ARCH=arm SUFFIX=-${ARCH} hf ;; *) fatal "unsupported architecture ${ARCH} " ;; esac }
if
变量匹配正则
1 2 3 4 branch=xxx_release_v2 if echo "$branch " | grep -q 'release' ; then echo "This is a release version." fi
命令执行正确
1 2 3 4 5 6 7 8 if curl -m 3 github.com ; then docker_hub=github.com ; elif curl -m3 ghproxy.com/https://github.com ; then docker_hub=ghproxy.com/https://github.com ; else echo "no docker registry" ; exit -1 ; fi
使用逻辑运算符 &&(和)和 ||(或)来组合多个条件
1 2 3 if [ $var -gt 10 ] && [ $var -lt 20 ]; then echo "Variable is between 10 and 20" fi
全单词匹配,以单词开头或空格为分界
1 2 3 4 5 6 7 8 9 10 #!/bin/bash version="Skip v1.0.0.beta tag creation in dry-run mode" pattern="v1.0.0" if [[ $version =~ (^|[[:space:]])$pattern ($|[[:space:]]) ]]; then echo "Match found" else echo "No match found" fi
=~
:正则表达式匹配操作符,用于判断左侧的字符串是否与右侧的正则表达式匹配。
(^|[[:space:]])
:表示匹配字符串的开头或者一个空格字符。
$pattern
:表示要匹配的模式,即变量 $pattern 的值。
($|[[:space:]])
:表示匹配字符串的结尾或者一个空格字符。
function
$0: 获取当前脚本或函数的名称
$1: 获取第一个参数
shift
获取第二个参数后面的所有参数,可以使用 shift 命令来移动参数位置,然后使用 $@或 $ 来获取剩余的参数。
1 2 3 4 print_args () { shift echo "The remaining arguments are: $@ " }
在这个函数中,shift 命令用于将第一个参数移动到 $1 中,将第二个参数移动到 $2 中,以此类推。然后,函数使用 $@来获取剩余的参数,并将它们作为一个单词列表输出。
例如,如果你调用 printargs 函数并传递 "hello"、“world"和"how"作为参数,它将打印出"The remaining arguments are: world how”。
返回值
函数可以使用 echo 命令来返回一个字符串。具体来说,echo 命令用于将一个或多个字符串输出到标准输出流中。如果需要将多个字符串连接起来返回,可以使用命令替换和引号来实现。
1 2 3 4 5 6 7 concat () { local result="$1$2 " echo $result } result=$(concat "hello" "world" ) echo "The result is: $result "
在这个函数中,$1 和 $2 分别表示第一个和第二个参数。函数使用 $1 和 $2 将它们连接起来,并将结果存储在名为 result 的本地变量中。最后,函数使用 echo 命令将 result 的值输出到标准输出流中。
:= 和 :-
在 shell 中:=
和 :-
是 bash shell 中的变量赋值操作符。它们的作用是在变量未定义或为空时,给变量赋默认值。
:=
是在变量未定义或为空时赋值
:-
是在变量为空时赋值
get dir to script
获取执行路径到脚本的相对路径
1 2 3 SCRIPT_DIR=$(dirname "$(readlink -f "$0 " ) " ) CURRENT_DIR=$(readlink -f "." ) RELATIVE_PATH=$(realpath --relative-to="$CURRENT_DIR " "$SCRIPT_DIR " )
使用当前执行路径和脚本所在路径计算相对路径
1 RELATIVE_PATH=$(dirname "$0 " )
使用脚本 $0
获取路径.
getopt
getopts 是 Bash shell 中用于解析命令行参数的工具。
处理多个参数值
如果处理多个参数值,可以使用一个循环来读取它们。例如
1 2 3 4 5 6 7 8 9 10 11 12 while getopts "a:" opt; do case $opt in a) for arg in "${OPTARG[@]} " ; do echo "Option a: $arg " done ;; \?) echo "Invalid option: -$OPTARG " >&2 ;; esac done
在这个例子中,-a 选项后面可以跟多个参数值,每个值都会被循环读取并处理。
处理长选项
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 OPTIONS=$(getopt -o a:b:c --long alpha:,beta:,gamma: -- "$@ " ) eval set -- "$OPTIONS " while true ; do case $1 in -a|--alpha) echo "Option alpha: $2 " shift 2 ;; -b|--beta) echo "Option beta: $2 " shift 2 ;; -c|--gamma) echo "Option gamma" shift ;; --) shift break ;; *) echo "Invalid option: $1 " >&2 exit 1 ;; esac done
处理必选参数
处理必选参数,可以在 getopts 循环外部检查它们是否存在。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 if [ -z "$1 " ]; then echo "Missing required argument: foo" >&2 exit 1 fi while getopts "a:" opt; do case $opt in a) echo "Option a: $OPTARG " ;; \?) echo "Invalid option: -$OPTARG " >&2 ;; esac done
在这个例子中,检查了是否存在必选参数 foo,如果不存在则退出脚本。
get filesystem type
获取文件系统类型
1 2 3 4 5 6 7 8 9 10 11 12 filesystem=$(df -T . | awk 'NR==2 {print $2}' ) if [[ $filesystem == "ext4" ]]; then echo "The file system is ext4." elif [[ $filesystem == "xfs" ]]; then echo "The file system is xfs." elif [[ $filesystem == "btrfs" ]]; then echo "The file system is btrfs." else echo "Unknown file system and skip the code check because of the performance." exit 0 fi
for
1 2 for f in *; do file $f ;done
command and check
执行命令并检查是否执行成功
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 status=0 pre-commit run --all-files || status=$? ls if [ $? -eq 0 ]; then echo "命令执行成功" else echo "命令执行失败" fi if command -v cmake &>2 /dev/null; then echo "cmake is working" fi
here doc(EOF)
Shell 脚本中使用的两种特殊的输入重定向语法
1 2 3 cat <<-'EOF' > temp.sh echo $VAR EOF
1 2 3 cat <<-EOF Hello World! # 前面的缩进在输出时,被忽略 EOF
更多使用示例
1 2 3 4 5 6 7 8 9 10 11 12 cat <<EOF | docker-compose up -f - # ... EOF cat <<EOF | tee /etc/yum.repos.d/kubernetes.repo # ... EOF cat > /etc/rancher/k3s/registries.yaml <<EOF # ... EOF
array or map
map 访问
1 2 3 4 5 6 7 declare -A patterns_mappatterns_map["category1" ]="pattern1" patterns_map["category2" ]="pattern2" patterns_map["category3" ]="pattern3" echo "Keys: ${!patterns_map[@]} " echo "Values: ${patterns_map[@]} "
str to array
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 input="[clash,devcontainer]" IFS=' ' read -r -a array <<< "$(echo $input | tr -d '[]' | tr ',' ' ') " for element in "${array[@]} " ; do echo $element done IFS=' ' read -ra ry <<< "$(echo ${input//,/ } | tr -d '[]') " for element in "${ry[@]} " ; do echo $element done array=$(echo $input | tr -d '[]' | tr ',' '\n' ) readarray -t array <<< "$array " for item in "${array[@]} " ; do echo "$item " done
string operation boilerplate
常用的字符串运算符:
{string#pattern}
: 从字符串的开头开始匹配并删除最短的 pattern。
{string##pattern}
: 从字符串的开头开始匹配并删除最长的 pattern。
{string/old/new}
: 替换字符串中第一个匹配的 old 为 new。
{string//old/new}
: 替换字符串中所有匹配的 old 为 new。
{string/#pattern/new}
: 如果字符串以 pattern 开头,则用 new 替换。
{string/%pattern/new}
: 如果字符串以 pattern 结尾,则用 new 替换。
links:
${string//old/new}
全局替换匹配操作中的 //
表示全局替换,即将字符串中的所有匹配项都替换。/ 是用于分隔替换的模式
和替换字符串
的字符。
1 2 3 4 echo ${string//,/ } echo ${string//: / } echo ${string//;/\n}
${string/%pattern/new}
结尾匹配操作中的 %
是一个模式运算符,用于从字符串的末尾开始匹配并删除指定模式的内容
1 2 3 4 5 6 7 8 echo "${filename%.*} " echo "${word%**} " echo "${number%[0-9]} " echo "${sentence% } "
envsubst
envsubst 用于文件变量替换
1 apt install gettext-base
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 export username=test cat <<EOF > a.bash echo "pwd is ${PWD}" echo "username is ${username}" EOF cat <<'EOF' | envsubst > b.bashecho "pwd is ${PWD} " echo "username is ${username} " EOF cat <<'EOF' | envsubst '${username}' >b.bashecho "pwd is ${PWD} " echo "username is ${username} " EOF
date
Linux 打印显示时间
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 $ echo $(date +%F) 2022-10-21 $ echo $(date +%R) 16:50 $ echo $(date +%T) 16:51:18 $ echo $(date +%A) Friday $ echo $(date +%Y/%m/%d) 2022/10/21 $ echo $(date +%H:%M:%S) 16:52:50 $ echo $(date +%F%n%T) 2022-10-21 16:53:26
echo
watch
1 2 3 4 5 6 7 8 watch -n1 minikube kubectl -- get pod -A watch -n 1 ls -l /path/to/file watch -n 1 ps aux watch -n 1 netstat -an
curl
-s/–silent: 静默,一旦发生错误,不会显示错误信息。不发生错误的话,会正常显示运行结果。
-w: 选项支持很多不同的格式占位符,以便可以输出 cURL 请求的各种指标。以下是常见的格式占位符:
%{time_total}:请求总时间,包括传输和处理时间。
%{time_namelookup}:DNS 解析时间。
%{time_connect}:建立连接所花费的时间。
%{time_appconnect}:SSL / TLS 握手和建立连接所花费的时间。
%{time_pretransfer}:从请求发出到开始传输数据所花费的时间。
%{time_starttransfer}:从请求发出到第一个字节接收到所花费的时间。
%{speed_download}:下载速度,以字节 / 秒为单位。
%{speed_upload}:上传速度,以字节 / 秒为单位。
%{http_code}:HTTP 响应码。
%{url_effective}:请求的 URL(包括任何重定向后的 URL)。
-d: --data-urlencode POST 方法传递数据,区别在于会自动将发送的数据进行 URL 编码。
-H: -H “头部信息” 传递多个头部信息
-m/–max-time: 设置最大传输时间 (s)
1 2 3 4 5 curl -s -w '\n%{http_code}\n' -d '{"log_verbose_level":1}' -X POST localhost:8000/v2/logging
sed
安装
pattern space and hold space
pattern space
sed 一次只能处理一行。因为它没有可视化模式,所以会创建一个 模式空间 (pattern space),这是一个内存空间,其中包含来自输入流的当前行(删除了尾部的任何换行符)。填充模式空间后,sed 将执行你的指令。当命令执行完时,sed 将模式空间中的内容打印到输出流,默认是 标准输出,但是可以将输出重定向到文件,甚至使用 --in-place=.bak 选项重定向到同一文件。然后,循环从下一个输入行再次开始。
hold space
为了在遍历文件时提供一点灵活性,sed 还提供了 保留空间 (hold space)(有时也称为 保留缓冲区 (hold buffer)),即 sed 内存中为临时数据存储保留的空间。你可以将保留空间当作剪贴板,实际上,这正是本文所演示的内容:如何使用 sed 复制 / 剪切和粘贴。
常用说明
-n
-n: 禁用显示输出。
1 sed -n -e '/three/h' example.txt
h H d
1 2 3 4 $ cat example.txt Line one Line three Line two
h: 以覆盖的方式复制到 hold space。
H: 以追加的方式复制匹配行到 hold space。
g: 获得 hold space 内容,并替代当前 pattern space 中的文本。
G: 获得 hold space 内容,并追加到当前 pattern space 文本的后面。
1 2 3 4 5 $ sed -n -e '/three/h;/three/d;/two/G;p' example.txt Line one Line two Line three
常用 sed 操作
这里总结了常用的 sed 使用模式样例。
a\ 在当前行下面插入文本。
i\ 在当前行上面插入文本。
c\ 把选定的行改为新的文本。
1 2 3 4 5 6 sed -i '/^#/ d' path/to/file sed -i '2i\ "default-runtime": "nvidia",' /etc/docker/daemon.json sed $'s/\r$//' ./install.sh > ./install.Unix.sh