概述
无论什么语言,在大型项目中,shell和markdown都是最常用的脚本构建工具,本文从kata-containers的项目脚本角度,学习shell和markdown的实用技巧。
tricks
shell
set
set -o errexit / set -e # 失败则退出模式
set -o pipefail # | 管道只返回最后一个命令的成功状态,在兼容多发行版时很有用
set -o errtrace # 此选项意味着如果脚本中任何命令失败,而且该命令在函数中或与函数相关的子shell中,则会触发ERR陷阱。基本上,这个选项可以让你捕获在函数内部发生的错误。
set +e # 失败不退出模式,一般只是临时开启
var
DOCKER_RUNTIME=${DOCKER_RUNTIME:-runc} # 默认值
export GOPATH=${GOPATH:-${HOME}/go} # env,方便传递给其他脚本
local exit_code="${?}" # 内部变量,只能用在function
typeset -r CONFIG_SH="config.sh" # 声明只读
declare -r CONFIG_SH="config.sh"
local -a bin_dirs=(
"/bin"
"/usr/bin"
"/usr/local/bin"
)
脚本执行模式
- source test.sh: 以当前shell环境执行脚本,因此语句副作用会在执行完成后留下,一般用于刷新PATH等变量
- . test.sh: 本质上和source相同
- bash test.sh: 使用bash解释器执行脚本,而不是默认的sh指向的解释器,不需要x权限,使用子环境
- /abs/test.sh: 需要脚本有x权限,使用子环境
- ./test.sh: 本质上和绝对路径相同
include script
lib_file="${script_dir}/../scripts/lib.sh"
source "$lib_file"
简单语句避免写if语句
[ "${TARGET_ARCH}" == "aarch64" ] && TARGET_ARCH=arm64 # 成功则执行
[ -n "${distro}" ] || usage 1 # 失败则执行
trap / handle err
打印出发生错误的行号。这可以帮助你在调试脚本时定位问题所在。
handle_error() {
local exit_code="${?}"
local line_number="${1:-}"
echo "Failed at $line_number: ${BASH_COMMAND}"
exit "${exit_code}"
}
trap 'handle_error $LINENO' ERR
trap after_stopping_container EXIT
常用判断器
- [ -n ]
- [ -d ]
- [ -z ]
- [ -e ]
- [ -x ]
- [ -eq ] [ == ]
- [ -ne ]
检测命令
if command -v selinuxenabled > /dev/null; then
set +e
which ${python_cmd} > /dev/null 2>&1
if [ $? -eq 0 ]; then
my_python=${python_cmd}
fi
pushd/popd
pushd/popd 相比 cd 更加好用
解析参数
parse_arguments()
{
[ "$#" -eq 0 ] && usage && return 0
while getopts a:hlo:r:t: opt
do
case $opt in
a) AGENT_VERSION="${OPTARG}" ;;
h) usage ;;
l) get_distros | sort && exit 0;;
o) OSBUILDER_VERSION="${OPTARG}" ;;
r) ROOTFS_DIR="${OPTARG}" ;;
t) get_test_config "${OPTARG}" && exit 0;;
*) die "Found an invalid option";;
esac
done
shift $(($OPTIND - 1))
distro="$1"
arch=$(uname -m)
}
main
main()
{
parse_arguments $*
other_func
}
main $*
markdown
include
include utils.mk
include ./tools/packaging/kata-deploy/local-build/Makefile
var
COMPONENTS =
COMPONENTS += libs
COMPONENTS += agent
STANDARD_TARGETS = build check clean install
KATA_DEBUG_REGISTRY ?= ""
伪目标
makefile默认以文件作为目标,并构建出一条文件依赖链。伪目标则不是文件,更像是一条命令,必须被用户显式执行。
.PHONY: \
all \
kata-tarball \
install-tarball \
default \
static-checks \
docs-url-alive-check
高级:宏 example
# 示例参数
ITEMS = item1 item2
PLATFORMS = platform1 platform2
# 初始化一个空变量用来存储所有目标
ALL_TARGETS =
# 定义一个宏,它用来根据参数创建规则
define create_rule
ALL_TARGETS += $(1)_$(2)
$(1)_$(2):
echo "Building $(1) for $(2)"
endef
define create_rule_list
$(foreach c,$(1),$(eval $(call create_rule_list2,$(c),$(2))))
endef
define create_rule_list2
$(foreach c,$(2),$(eval $(call create_rule,$(1),$(c))))
endef
$(foreach item, $(ITEMS), \
$(foreach platform, $(PLATFORMS), \
$(eval $(call create_rule,$(item),$(platform))) \
) \
)
# $(eval $(call create_rule_list,$(ITEMS),$(PLATFORMS)))
.PHONY: all
all: $(ALL_TARGETS)
.PHONY: show-targets
show-targets:
echo $(ALL_TARGETS)
调试
# -n 表示只打印执行的命令,而不实际执行
make -n