shell script
脚本其实就是短小的、用来让计算机自动化完成一系列工作的程序,这类程序可以用文本编辑器修改,不需要编译,通常是解释运行的。
第一个shell脚本
#!/bin/bash
echo "hello World !"
#!是一个约定的标记,告诉系统脚本需要什么解释器来执行
echo命令用于向窗口输出文本
chmod +x ./test.sh
./test.sh
变量
定义变量
在shell编程中,变量是用于存储数据值的名称;在定义变量时,变量名不加美元符号($,PHP语言中需要)
my_name="Lyt"
- 变量名和等号之间不能有空格
- 只包含字母(大小写敏感)、数字(不能以数字开头)、下划线(_)
- 避免shell关键字(例:if 、then 、else 、fi 、for 、while等)
- 使用大写字母表示常量
使用变量
使用一个定义过的变量,只要在变量名前加美元符号即可。
my_name="Lyt"
echo ${myname}
$() 与 ${}
在 shell 编程中,圆括号 () 和花括号 {} 的使用很容易混淆,但它们的使用是不同的:
- 花括号包裹变量名,如 ${a},表示使用变量 a 的值,在不引起歧义的情况下可以省略花括号;
- 圆括号可用于包裹 shell 命令,如 $(CMD) 命令替换,和 `CMD` 效果相同,结果为该命令的输出。
例如:
kernel=$(uname -r)
echo $kernel # 例如输出:5.8.0-55-generic
linux=`uname -r`
echo $linux # 同样输出:5.8.0-55-generic
只读变量
使用readonly命令可以将变量定义为只读变量,只读变量的值不能被改变
my_name="Lyt"
readonly my_name
删除变量
变量被删除后不能再次使用。unset命令不能删除只读变量
unset my_name
内部变量
特殊变量
注:
- $?也可表示函数返回值
- $1 代表第一个参数 超过及第10个参数不能写成 10 , 要写成 10,要写成 10,要写成{10}
其他内部变量
除了以 $ 符开头的特殊变量,下面这些内部变量在shell编程中也较为常用
下面例子加深理解
#!/bin/bash
read
echo " PPID : $PPID"
echo " PWD : $PWD"
echo " LINE : $LINENO"
echo " RANDOM : $RANDOM"
echo " REPLY : $REPLY"
echo "$OPTARG, $OPTIND"
echo "RUN TIME : $SECONDS"
运行脚本
$ ./shell_variables.sh
App
PPID : 7971
PWD : /home/
LINE : 6
RANDOM : 12180
REPLY : App
RUN TIME : 3
环境变量
使用 env 命令可以查看所有环境变量(都为大写):
$ env
SHELL=/bin/sh
EDITOR=vi
PWD=/home/rudy
LOGNAME=rudy
XDG_SESSION_TYPE=tty
HOME=/home/rudy
LANG=C
QT_QPA_PLATFORM=wayland
...
除了系统默认配置的环境变量,我们也可以手动添加环境变量,添加的方法是通过 export 命令。
例如在嵌入式开发中常常需要设置 ARCH 和 CROSS_COMPILE 环境变量:
export ARCH=arm64
export CROSS_COMPILE=aarch64-poky-linux-
或者修改当前的环境变量,例如将当前用户主目录下的 .local/bin 目录添加到 PATH 环境变量:
export PATH="/home/$(whoami)/.local/bin:$PATH"
如果在 shell 终端执行上述 export 命令,则该环境变量只会对当前 shell 及其子 shell 有效;如果想要环境变量对所有用户生效,则可以将 export 命令保存到 /etc/profile 文件;如果只想对特定用户生效,则可以保存到 ~/.bashrc 文件。
变量类型
my_name="Lyt" #字符串
declare -i my_age=25 #整数
my_array=(1 2 3 4 5) #数组
declare -A associative_array #关联数组
associative_array["name"]="Lyt"
associative_array["age"]=25
- 字符串变量可用单引号或双引号来定义
- 可以使用declare或typeset命令来声明整数变量
- 特殊变量:$0表示脚本的名称;$1,$2等表示脚本的参数; $#表示传递给脚本的参数数量; $?表示上一个命令的退出状态;
字符串
单引号字符串限制:
- 单引号的任何字符都会原样输出,单引号字符串中的变量时无效的
- 单引号字符串中不能出现单独的一个单引号(对单引号使用转移符后也不行),可以成对出现,作为字符串拼接使用。
双引号的优点:
- 双引号里可以有变量
- 双引号里可以出现转义字符
my_name="Lyt make shell script!"
获取字串长度:echo ${#my_name}
提取子字串: echo ${my_name:1:4}
查找'i'或'o'字串: echo `expr index "${my_name}" io` #输出4即为i的下标
对字符串进行操作 (# ## % %%)
# ##表示从左边开始删除。一个#表示从左边删除到第一个指定的字符;两个#表示从左边删除到最后一个指定的字符。
% %%表示从右边开始删除。一个%表示从右边删除到第一个指定的字符;两个%表示从左边删除到最后一个指定的字符。
注:删除包括了指定的字符本身
eg:
#!/bin/bash
# 字符串截取(界定字符本身也会被删除)
str="www.runoob.com/linux/linux-shell-variable.html"
echo "str : ${str}"
echo "str#*/ : ${str#*/}" # 从 字符串开头 删除到 左数第一个'/'
echo "str##*/ : ${str##*/}" # 从 字符串开头 删除到 左数最后一个'/'
echo "str%/* : ${str%/*}" # 从 字符串末尾 删除到 右数第一个'/'
echo "str%%/* : ${str%%/*}" # 从 字符串末尾 删除到 右数最后一个'/'
echo
echo "str#/* : ${str#/*}" # 无效果
echo "str##/* : ${str##/*}" # 无效果
echo "str%*/ : ${str%*/}" # 无效果
echo "str%%*/ : ${str%%*/}" # 无效果
输出结果:
str : www.runoob.com/linux/linux-shell-variable.html
str#*/ : linux/linux-shell-variable.html
str##*/ : linux-shell-variable.html
str%/* : www.runoob.com/linux
str%%/* : www.runoob.com
str#/* : www.runoob.com/linux/linux-shell-variable.html
str##/* : www.runoob.com/linux/linux-shell-variable.html
str%*/ : www.runoob.com/linux/linux-shell-variable.html
str%%*/ : www.runoob.com/linux/linux-shell-variable.html
数组
读取数组元素值的一般格式:${数组名[下标]}
value=${my_name[2]}
使用@符号可以获取数组中的所有元素
echo ${my_name[@]}
获取数组的长度
length=${#my_name[@]} #获取数组元素个数
#或者
lengh=${#my_name[*]}
获取单个元素的长度
length=${#array_name[n]}
关联数组
可以使用任意的字符串、或者整数作为下标来访问数组元素。关联数组使用declare命令来声明,语法格式如下:
declare -A array_name
-A 选项就是用于声明一个关联数组
实例:
declare -A site=(["name"]="Lyt" ["age"]="25")
declare -A site1
site1["color"]="red"
site1["fruit"]="apple"
echo ${site["name"]}
echo ${!site[*]} #获取数组的所有键
注释:单行注释用 #
多行注释格式:
: '
注释内容
'
基本运算符
#!/bin/bash
val=`expr 2 + 2`
echo "两数之和为:${val}"
注:
- 表达式和运算符之间要有空格,例如2+2是不对的,必须写成2 + 2
- 完整的表达式要被 ` ` 包含,注意不是常用的单引号是反引号
- 也可以写成val=$(expr 2 + 2)
算数运算符
下表列出常用的算数运算符,假定变量a为10,变量b为20:
注:
- 条件表达式要放在方括号之间,并且要有空格,例如:[ a = = a== a==b]是错误的,必须写成[$a == $b]
- 双小括号表示其中进行数字类型的计算(而且只支持整型),双小括号中还支持布尔值判定,并且当被双小括号框中,整体就应该被看成一个变量。另外,双小括号中支持 C 语言语法规则,可以不加美元符,可以再加单小括号把一些运算先括起来等。
# 默认 a 是字符串类型
a=1;
# 把 a 看成数字,改变前面定义的变量时,必须要加双小括号,
# 或者用 let 语句,否则会把其视为字符串类型
((a++));
let "a++";
# 输出,双小括号应该被看成一个变量
echo $((a+1));
expr 是一款表达式计算工具,使用它能在 shell 中完成表达式的求值操作。但需要注意,expr 表达式要使用反引号包裹,并且表达式和运算符之间要有空格。
关系运算符
关系运算符只支持数字,不支持字符串,除非字符串的值是数字。假定a为10,b为20。
注:在 [ ] 表达式中,常见的 > ,< 需要加转义字符,表示字符串大小比较,以asci码位置作为比较。不直接支持 >, < 运算符,还有逻辑运算符|| ,&& ,它需要-a ,-o 表示
在 [ [ ] ] 表达式中,[ [ ] ] 运算符只是 [ ] 运算符的扩充,能够支持 > , < 符号运算不需要转义符,它还是以字符串比较大小,里面支持逻辑运算符: || && ,不再使用 -a ,-o
布尔运算符
假定a为10,b为20
逻辑运算符
逻辑运算符实例:
command1 && command2 #命令1执行成功后,命令2才执行
command1 || command2 #命令1执行失败后,命令2才执行
#注:主要用于连接两条命令,不能通过中括号来连接两个测试条件
[ $age=25 ] && echo "age is 25" #当前年龄为25时,才会输出后面语句
[ $myname=Lyt ] || echo "name is bot Lyt" #当用户不是Lyt时,则输出后面语句
字符串运算符
假定a为“abc” b为“efg”
文件测试运算符
文件测试运算符用于检测unix文件的各种属性
注:
- -S 判断某文件是否socket
- -L 检测文件是否存在并且是一个符号链接
输出输入
echo命令
显示输入值
read 命令从标准输入中读取一行,并把输入行的每个字段的值指定给shell变量
#!/bin/sh
read name
echo "${name} is a test"
#显示换行
echo -e "ok! \n" #-e 开启转义
#显示不换行
echo -e "ok! \c"
#显示结果定向至文件
echo "It is a test" > myfile
#显示命令执行结果
echo `date` #结果将显示当前日期
read介绍
read命令一个一个词组接收输入的参数,每个词组需要使用空格进行分割;如果输入的词组大于需要的参数个数,则多出来的词组将被作为整体为最后一个参数接收。
test.sh
#!/bin/sh
read firstr seconstr
echo "第一个参数:${firstr};第二个参数:${seconstr}"
执行测试:
sh test.sh
一 二 三 四
第一个参数:一,第二个参数:二 三 四
read 参数含义:
read -p "请输入一段文字:" -n 6 -t 5 -s password
echo -e "\npassword is ${password}"
参数说明:
- -p 输入提示文字
- -n 输入字符长度限制(达到6位,自动结束)
- -t 输入限时
- -s 隐藏输入内容
管道
管道在 Shell 中被广泛使用,可以用竖杠“ | ”表示。它的一般形式如下:
命令1 | 命令2
表示把命令1的输出通过管道传递给命令2作为输入。
举个栗子:我们先执行命令 ls,列出当前文件名,然后将结果送入管道中,进而 wc 从管道读出这些信息,并计算总共有几个单词:
$ ls | wc -w
重定向
> 重定向输出到某个位置,替换原有文件的所有内容
>> 重定向追加到某个位置,在原有文件的末尾添加内容
< 重定向输入某个位置文件
2> 重定向错误输出
2>> 重定向错误追加输出到文件末尾
&> 混合输出错误的和正确的输出
流程控制
if语法格式
if condition
then
command1
command2
...
commandN
fi
写成一行(终端命令提示符)
if [ $(ps -ef | grep -c "ssh") -gt 1];then echo "true";fi
if else 语法格式
if condition
then
command1
command2
...
commandN
else
command
fi
if else-if else 语法格式
if condition1
then
command1
elif condition2
then
command2
else
commandN
fi
注:
if else 的 [...] 判断语句中大于使用-gt,小于使用-lt
eg:
if [ "$a" -gt "$b"];then
...
fi
如果使用 ((...)) 作为判断语句,大于和小于可以直接使用 > 和 <
if (( a > b ));then
...
if
for 循环语法:
for var in item1 item2 ... itemN
do
command1
command2
...
commandN
done
写成一行:
for var in item1 item2 ... itemN;do command1;command2 ... done;
示例:
#!/bin/bash
for str in This is a string
do
echo $str
done
输出结果:
This
is
a
string
while语句
while condition
do
command
done
示例:
#!/bin/bash
int=1
while(( $int<=5 ))
do
echo $int
let "int++"
done
运行脚本,输出:
1
2
3
4
5
Bash let命令:
until循环语法格式
#condition一般为条件表达式,如果返回值为false,则继续执行循环体,否则跳出循环
until condition
do
command
done
until 循环执行一系列命令直至条件为ture时停止,until 循环与while 循环在处理方式上刚好相反。
一般while循环优于until 循环,但在某些时候也是极少数情况下,until 循环更加有用
case … esac
case 变量 in
模式1)
command1
command2
;;
模式2)
command1
command2
;;
esac
case … esac为多选择语句,与switch … case 语句类似,是一种多分枝选择结构,每个case分支用 ‘ )’ 开始,用两个分号 ‘ ;; ’ 表示break, esac作为结束标记
示例
#!/bin/bash
read num
case $num in
1) echo "你输入的数字为1"
;;
2) echo "你输入的数字为2"
;;
*) echo "你没有输入1 或 2"
;;
esac
shell 函数
[ function ] funname [()]
{
action;
[return int;]
}
说明:
- 可以带function fun() 定义,也可以直接fun() 定义,不带任何参数
- 参数返回,可以显示加:return 返回,如果不加,将以最后一条命令运行结果,作为返回值。return 后跟数值n( 0-255)
示例:
#!/bin/bash
demoFun(){
echo "hello world !"
}
demoFun
shell 输出 / 输入重定向
注:文件描述符0 通常时标准输入(STDIN),1是标准输出(STDOUT),2是标准错误输出(STDERR)
将stderr重定向到file : command 2>file
将stdout 和stderr合并后重定向到file :command > file 2>&1
示例
#!/bin/bash -e
KERNELS=$(ls | grep kernel- || true)
update_kernel()
{
# Fallback to current kernel
RK_KERNEL_VERSION=${RK_KERNEL_VERSION:-$(kernel_version)}
# Fallback to 5.10 kernel
RK_KERNEL_VERSION=${RK_KERNEL_VERSION:-5.10}
# Update .config
KERNEL_CONFIG="RK_KERNEL_VERSION=\"$RK_KERNEL_VERSION\""
if ! grep -q "^$KERNEL_CONFIG$" "$RK_CONFIG"; then
sed -i "s/^RK_KERNEL_VERSION=.*/$KERNEL_CONFIG/" "$RK_CONFIG"
"$RK_SCRIPTS_DIR/mk-config.sh" olddefconfig &>/dev/null
fi
[ "$(kernel_version)" != "$RK_KERNEL_VERSION" ] || return 0
# Update kernel
KERNEL_DIR=kernel-$RK_KERNEL_VERSION
notice "switching to $KERNEL_DIR"
if [ ! -d "$KERNEL_DIR" ]; then
error "$KERNEL_DIR not exist!"
exit 1
fi
rm -rf kernel
ln -rsf $KERNEL_DIR kernel
}
do_build()
{
check_config RK_KERNEL RK_KERNEL_CFG || false
if [ "$DRY_RUN" ]; then
notice "Commands of building $1:"
else
message "=========================================="
message " Start building $1"
message "=========================================="
fi
run_command $KMAKE $RK_KERNEL_CFG $RK_KERNEL_CFG_FRAGMENTS
if [ -z "$DRY_RUN" ]; then
"$RK_SCRIPTS_DIR/check-kernel.sh"
fi
case "$1" in
kernel-config | kconfig)
KERNEL_CONFIG_DIR="kernel/arch/$RK_KERNEL_ARCH/configs"
run_command $KMAKE menuconfig
run_command $KMAKE savedefconfig
run_command mv kernel/defconfig \
"$KERNEL_CONFIG_DIR/$RK_KERNEL_CFG"
;;
kernel*)
run_command $KMAKE "$RK_KERNEL_DTS_NAME.img"
# The FIT image for initrd would be packed in rootfs stage
if [ -n "$RK_BOOT_FIT_ITS" ] && \
[ -z "$RK_ROOTFS_INITRD" ]; then
run_command "$RK_SCRIPTS_DIR/mk-fitimage.sh" \
"kernel/$RK_BOOT_IMG" \
"$RK_BOOT_FIT_ITS" \
"$RK_KERNEL_IMG" "$RK_KERNEL_DTB" \
"kernel/resource.img"
fi
if [ "$RK_SECURITY" ]; then
if [ "$RK_SECURITY_CHECK_BASE" ]; then
run_command \
"$RK_SCRIPTS_DIR/mk-security.sh" \
sign boot "kernel/$RK_BOOT_IMG" \
$RK_FIRMWARE_DIR/
fi
else
run_command ln -rsf "kernel/$RK_BOOT_IMG" \
"$RK_FIRMWARE_DIR/boot.img"
fi
[ -z "$DRY_RUN" ] || return 0
"$RK_SCRIPTS_DIR/check-power-domain.sh"
"$RK_SCRIPTS_DIR/check-security.sh" kernel dts
if [ "$RK_WIFIBT_CHIP" ] && \
! grep -wq wireless-bluetooth "$RK_KERNEL_DTB"; then
error "Missing wireless-bluetooth in $RK_KERNEL_DTS!"
fi
;;
modules) run_command $KMAKE modules ;;
esac
}
build_recovery_kernel()
{
check_config RK_KERNEL || false
if [ "$DRY_RUN" ]; then
notice "Commands of building $1:"
else
message "=========================================="
message " Start building $1"
message "=========================================="
fi
if [ -z "$RK_KERNEL_RECOVERY_CFG" ]; then
RECOVERY_KERNEL_DIR=kernel
do_build kernel
else
RECOVERY_KERNEL_DIR="$RK_OUTDIR/recovery-kernel"
run_command mkdir -p "$RECOVERY_KERNEL_DIR"
# HACK: Fake mrproper
run_command tar cf "$RK_OUTDIR/kernel.tar" \
--remove-files --ignore-failed-read \
kernel/.config kernel/include/config \
kernel/arch/$RK_KERNEL_ARCH/include/generated
KMAKE="$KMAKE O=$RECOVERY_KERNEL_DIR"
run_command $KMAKE $RK_KERNEL_RECOVERY_CFG
run_command $KMAKE "$RK_KERNEL_DTS_NAME.img"
run_command tar xf "$RK_OUTDIR/kernel.tar"
run_command rm -f "$RK_OUTDIR/kernel.tar"
fi
run_command ln -rsf \
"$RECOVERY_KERNEL_DIR/${RK_KERNEL_IMG#kernel/}" \
"$RK_OUTDIR/recovery-kernel.img"
run_command ln -rsf \
"$RECOVERY_KERNEL_DIR/${RK_KERNEL_DTB#kernel/}" \
"$RK_OUTDIR/recovery-kernel.dtb"
run_command ln -rsf \
"$RECOVERY_KERNEL_DIR/resource.img" \
"$RK_OUTDIR/recovery-resource.img"
}
# Hooks
usage_hook()
{
for k in $KERNELS; do
echo -e "$k[:cmds] \tbuild kernel ${k#kernel-}"
done
echo -e "kernel[:cmds] \tbuild kernel"
echo -e "recovery-kernel[:cmds] \tbuild kernel for recovery"
echo -e "modules[:cmds] \tbuild kernel modules"
echo -e "linux-headers[:cmds] \tbuild linux-headers"
echo -e "kernel-config[:cmds] \tmodify kernel defconfig"
echo -e "kconfig[:cmds] \talias of kernel-config"
echo -e "kernel-make[:<arg1>:<arg2>] \trun kernel make"
echo -e "kmake[:<arg1>:<arg2>] \talias of kernel-make"
}
clean_hook()
{
[ ! -d kernel ] || make -C kernel distclean
rm -rf "$RK_OUTDIR/recovery-*"
rm -f "$RK_FIRMWARE_DIR/linux-headers.tar"
rm -rf "$RK_FIRMWARE_DIR/boot.img"
}
INIT_CMDS="default $KERNELS"
init_hook()
{
load_config RK_KERNEL_CFG
check_config RK_KERNEL_CFG &>/dev/null || return 0
# Priority: cmdline > custom env > .config > current kernel/ symlink
if echo $1 | grep -q "^kernel-"; then
export RK_KERNEL_VERSION=${1#kernel-}
notice "Using kernel version($RK_KERNEL_VERSION) from cmdline"
elif [ "$RK_KERNEL_VERSION" ]; then
export RK_KERNEL_VERSION=${RK_KERNEL_VERSION//\"/}
notice "Using kernel version($RK_KERNEL_VERSION) from environment"
else
load_config RK_KERNEL_VERSION
fi
update_kernel
}
PRE_BUILD_CMDS="kernel-config kconfig kernel-make kmake"
pre_build_hook()
{
check_config RK_KERNEL RK_KERNEL_CFG || false
source "$RK_SCRIPTS_DIR/kernel-helper"
message "Toolchain for kernel:"
message "${RK_KERNEL_TOOLCHAIN:-gcc}"
echo
case "$1" in
kernel-make | kmake)
shift
[ "$1" != cmds ] || shift
if [ "$DRY_RUN" ]; then
notice "Commands of building ${@:-stuff}:"
else
message "=========================================="
message " Start building $@"
message "=========================================="
fi
if [ ! -r kernel/.config ]; then
run_command $KMAKE $RK_KERNEL_CFG \
$RK_KERNEL_CFG_FRAGMENTS
fi
run_command $KMAKE $@
;;
kernel-config | kconfig)
do_build $@
;;
esac
if [ -z "$DRY_RUN" ]; then
finish_build $@
fi
}
pre_build_hook_dry()
{
DRY_RUN=1 pre_build_hook $@
}
BUILD_CMDS="$KERNELS kernel recovery-kernel modules"
build_hook()
{
check_config RK_KERNEL RK_KERNEL_CFG || false
source "$RK_SCRIPTS_DIR/kernel-helper"
message "Toolchain for kernel:"
message "${RK_KERNEL_TOOLCHAIN:-gcc}"
echo
case "$1" in
recovery-kernel) build_recovery_kernel $@ ;;
kernel-*)
if [ "$RK_KERNEL_VERSION" != "${1#kernel-}" ]; then
notice "Kernel version overrided: " \
"$RK_KERNEL_VERSION -> ${1#kernel-}"
fi
;&
*) do_build $@ ;;
esac
finish_build build_$1
}
build_hook_dry()
{
DRY_RUN=1 build_hook $@
}
POST_BUILD_CMDS="linux-headers"
post_build_hook()
{
check_config RK_KERNEL RK_KERNEL_CFG || false
source "$RK_SCRIPTS_DIR/kernel-helper"
[ "$1" = "linux-headers" ] || return 0
shift
[ "$1" != cmds ] || shift
OUTPUT_FILE="${1:-"$RK_OUTDIR"}/linux-headers.tar"
mkdir -p "$(dirname "OUTPUT_DIR")"
HEADER_FILES_SCRIPT=$(mktemp)
if [ "$DRY_RUN" ]; then
notice "Commands of building linux-headers:"
else
notice "Saving linux-headers to $OUTPUT_FILE"
fi
run_command $KMAKE $RK_KERNEL_CFG $RK_KERNEL_CFG_FRAGMENTS
run_command $KMAKE $RK_KERNEL_IMG_NAME
cat << EOF > "$HEADER_FILES_SCRIPT"
{
# Based on kernel/scripts/package/builddeb
find . arch/$RK_KERNEL_ARCH -maxdepth 1 -name Makefile\*
find include -type f -o -type l
find arch/$RK_KERNEL_ARCH -name module.lds -o -name Kbuild.platforms -o -name Platform
find \$(find arch/$RK_KERNEL_ARCH -name include -o -name scripts -type d) -type f
find arch/$RK_KERNEL_ARCH/include Module.symvers -type f
echo .config
} | tar --no-recursion --ignore-failed-read -T - \
-cf "$OUTPUT_FILE"
EOF
run_command cd "$RK_SDK_DIR/kernel"
cat "$HEADER_FILES_SCRIPT"
if [ -z "$DRY_RUN" ]; then
. "$HEADER_FILES_SCRIPT"
fi
case "$RK_KERNEL_KBUILD_ARCH" in
host) run_command tar -uf "$OUTPUT_FILE" scripts tools ;;
*)
run_command cd "$RK_KBUILD_DIR/$RK_KERNEL_KBUILD_ARCH"
run_command cd "linux-kbuild-$RK_KERNEL_VERSION_REAL"
run_command tar -uf "$OUTPUT_FILE" .
;;
esac
run_command cd "$RK_SDK_DIR"
rm -f "$HEADER_FILES_SCRIPT"
}
post_build_hook_dry()
{
DRY_RUN=1 post_build_hook $@
}
source "${RK_BUILD_HELPER:-$(dirname "$(realpath "$0")")/../build-hooks/build-helper}"
case "${1:-kernel}" in
kernel-config | kconfig | kernel-make | kmake) pre_build_hook $@ ;;
kernel* | recovery-kernel | modules)
init_hook $@
build_hook ${@:-kernel}
;;
linux-headers) post_build_hook $@ ;;
*) usage ;;
esac