Live in the present

Msclock's Notes

5w2h

5W2H 是一种问题分析方法,用于解决问题或制定计划。5W 代表 What、Why、Where、When、Who,2H 代表 How、How much。这种方法可以帮助我们全面地了解问题或计划,从而更好地解决问题或制定计划。

mindmap
  root((5w2h))
    1.5w
      1.why 为什么
      2.what 是什么
      3.where 何处
      4.when 何时
      5.who 谁负责
    2.2h
      1.how 怎么做
      2.how much 花销

5w 的内容

  • why—— 为什么?为什么要这么做?理由何在?原因是什么?

  • what—— 是什么?目的是什么?作什么工作?

  • where—— 何处?在哪里做?从哪里入手?

  • when—— 何时?什么时间完成?什么时机最适宜?

  • who—— 谁?有谁来承担?谁来完成?谁负责?

2h 的内容

  • how—— 怎么做?如何提高效率?如何实施?方法怎么样?

  • how much—— 多少?做到什么程度?数量如何?质量水平如何?费用产出如何?

阅读全文 »

资源

资源 组织 类型
wangdoc

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
#-------------------------------------------------------------------------------------------------------------
# Copyright (c) msclock. All rights reserved.
# Licensed under the MIT License.
#-------------------------------------------------------------------------------------------------------------
#
#
# shellcheck disable=SC2034,SC2086
#
# Maintainer: msclock

# setup_arch set arch and suffix,
# fatal if architecture not supported.
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
  • n: 用于判断字符串是否非空,如果字符串的长度大于 0,则返回 true,否则返回 false。

  • z: 用于判断字符串是否为空,如果字符串的长度等于 0,则返回 true,否则返回 false。

全单词匹配,以单词开头或空格为分界

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 ls; then`
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 脚本中使用的两种特殊的输入重定向语法

  • ‘EOF’: 使用单引号将 EOF 引起来可以防止文本中的变量扩展和命令替换

1
2
3
cat <<-'EOF' > temp.sh
echo $VAR # $VAR 输出到文件时, 不会被环境变量替换
EOF
  • -: 允许使用 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 <<EOF > /etc/rancher/k3s/registries.yaml
cat > /etc/rancher/k3s/registries.yaml <<EOF
# ...
EOF

array or map

map 访问

1
2
3
4
5
6
7
declare -A patterns_map
patterns_map["category1"]="pattern1"
patterns_map["category2"]="pattern2"
patterns_map["category3"]="pattern3"

echo "Keys: ${!patterns_map[@]}" # keys are treated as separate elements
echo "Values: ${patterns_map[@]}" # values are treated as separate elements

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
# here doc
cat <<EOF > a.bash
echo "pwd is ${PWD}"
echo "username is ${username}"
EOF

# envsubst
cat <<'EOF' | envsubst > b.bash
echo "pwd is ${PWD}"
echo "username is ${username}"
EOF

# 只替换 username
cat <<'EOF' | envsubst '${username}' >b.bash
echo "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

  • -e: 启动转义

  • -n: 不追加换行

watch

1
2
3
4
5
6
7
8
# 每个1s运行后面的命令
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 编码。

    • URL 编码:将特殊字符替换编码,如空格替换为 %20。
    • @: 读取本地文件,请求,如 curl -d ‘@./data.txt’ https://wangchujiang.com/upload
  • -H: -H “头部信息” 传递多个头部信息

  • -m/–max-time: 设置最大传输时间 (s)

1
2
3
4
5
# -s silent: 静默输出
# -w '\n%{http_code}\n': 添加换行格式化输出 http 的 code 码
# -d '{"log_verbose_level":1}': 请求输出
# —X POST: 请求 POST 方法
curl -s -w '\n%{http_code}\n' -d '{"log_verbose_level":1}' -X POST localhost:8000/v2/logging

sed

安装

  • MacOS 用户可以在 MacPorts 或 Homebrew 上找到 GNU sed。

  • 在 Windows 上,你可以通过 Chocolatey 来 安装 GNU 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
# 在第二行后插入一行 "default-runtime": "nvidia",
sed -i '2i\ "default-runtime": "nvidia",' /etc/docker/daemon.json
# bash\r: No such file or directory
sed $'s/\r$//' ./install.sh > ./install.Unix.sh
阅读全文 »

本文总结了架构设计的基本理念。

阅读全文 »

resource

资源 组织 类型
devops-exercises bregman-arie 基础

k8s

什么是 k8s

  • 开源的容器编排工具

  • 由 google 开发

  • 帮助在不同的部署环境中管理容器应用

k8s 解决的问题

  • 将传统铁板一块的应用转为微服务管理

  • 增加容器的使用便利

  • 高效管理成千上百的容器的能力

k8s 提供的编排功能

  • 高可用且无关机时延

  • 可扩展性或高性能

  • 容灾,备份和还原

links:

阅读全文 »

主要总结 airflow 框架使用经验。

Beginner

  • Airflow Introduction

  • Run Airflow in Python Env

阅读全文 »

OPENVPN

这里介绍了使用 openvpn 在 linux 上的使用。

阅读全文 »

DNS

DNS 至提供域名解析及映射服务。访问 github 等 ip 多变的网址,需要频繁更新映射。部分原因如下:

  • 有时,可能无法访问某些网站。

  • 解决网络相关问题时。

  • DNS 解析程序更改后。

运行刷新 DNS 缓存时,这将破坏缓存中的 DNS 条目,并根据新配置的 DNS 设置执行后续查询以解析域。

阅读全文 »
0%