前言
要写一个linux安装程序, 发现细节写的不自如.
边写边查, 实在受不了, 效率太低了.
还是要系统的看看书. 达到写脚本的时候, 只关注逻辑, 而不用关心语法, 这才到位.
看了一段书, 练习一下, 知识点如下:
* 宏的定义和使用
* 数学表达式的用法
* 函数的控制 : 入参个数, 入参取值, 出参赋值, 函数返回值.
* 数值的比较, 字符串的比较.
* 循环的控制, 系统变量的替换和恢复, 循环的嵌套(脚本中的内层循环, 还是用函数来替代较好维护)
* 脚本不是强类型语言,变量不存在,也不报错。所有变量的命令,开始要想好命名规则,如果后来想改,容易搞乱了。如果使用了不存在的变量,进行逻辑判断,导致逻辑错误,要排查很久。si对脚本的支持不行,连单词高亮都搞不定。可能还要设置吧?
实验效果
--------------------------------------------------------------------------------
| @file demo_002.sh
| @brief wrap a shell script functin to check user exist
--------------------------------------------------------------------------------
| check user exist
| 1.0.0.2
| 2018-02-11 18:22
--------------------------------------------------------------------------------
| 2018_02_11_18_27_23
| /bin/bash
| zh_CN.UTF-8
| root
--------------------------------------------------------------------------------
user [root] exist, user home dir = /root
user [dev] not exist, but have home dir, user home dir = /home/dev
user [user_not_exist] not exist
--------------------------------------------------------------------------------
| END
--------------------------------------------------------------------------------
实验脚本
# !/bin/bash
# @file demo_002.sh
# @brief wrap a shell script functin to check user exist
# @note
# function return code must >= 0, not a string
#
# $0 is this.sh 's path name, e.g. ./demo_001.sh
# $# is fuction's argc
# $@ is fuction's argv
# $1 is this sh function's parameter 1
# $2 is this sh function's parameter 2
# ...
# $N is this sh function's parameter N
# $? is function's return code
#
# print env macro value
#
# default IFS on debian is '\n'
# echo "IFS = [$IFS]"
#
# compare int value
# -eq -ge -gt -le -lt -ne
#
# compare string
# = != < > -n -z
#
# var name rules
# rc means : return code, e.g. 0, 1, 2
# rv means : return value, e.g. "some string"
#
# global var name rules
# g_var_name__fun_name
#
# --------------------------------------------------------------------------------
# define macro
# --------------------------------------------------------------------------------
PROG_NAME="check user exist"
PROG_VER="1.0.0.2"
PROG_TIME="2018-02-11 18:22"
IND_CHAR=-
LINE10=${IND_CHAR}${IND_CHAR}${IND_CHAR}${IND_CHAR}${IND_CHAR}${IND_CHAR}${IND_CHAR}${IND_CHAR}${IND_CHAR}${IND_CHAR}
LINE80=${LINE10}${LINE10}${LINE10}${LINE10}${LINE10}${LINE10}${LINE10}${LINE10}
WALL_CHAR='|'
# --------------------------------------------------------------------------------
# global value
# --------------------------------------------------------------------------------
#
# err code define
#
g_err_code_base=0
g_err_code_ok=$(echo "scale=4; $g_err_code_base + 0" | bc)
g_err_code_err=$(echo "scale=4; $g_err_code_base + 1" | bc)
g_err_code_user_not_exist=$(echo "scale=4; $g_err_code_base + 2" | bc)
g_err_code_user_not_exist_but_have_home_dir=$(echo "scale=4; $g_err_code_base + 3" | bc)
# row info below
# games:x:5:60:games:/usr/games:/bin/sh
# one row have 7 fields, indicate char is ':'
# field 0 is username
# field 5 is home dir
#
g_etc_passwd_row_field_index_user_name=0
g_etc_passwd_row_field_index_home_dir=5
# --------------------------------------------------------------------------------
# init
# --------------------------------------------------------------------------------
function func_init() {
local i_index=0
clear
# print 25 empty lines for run result
for (( i_index=0; i_index < 25; i_index++ ))
do
echo
done
}
# --------------------------------------------------------------------------------
# uinit
# --------------------------------------------------------------------------------
function func_uinit() {
exit 0
}
# --------------------------------------------------------------------------------
# show title
# --------------------------------------------------------------------------------
function func_show_title() {
echo -e "${LINE80}"
echo -e -n "${WALL_CHAR}"
echo -e "\t@file\tdemo_002.sh"
echo -e -n "${WALL_CHAR}"
echo -e "\t@brief\twrap a shell script functin to check user exist"
echo -e "${LINE80}"
}
# --------------------------------------------------------------------------------
# show tail
# --------------------------------------------------------------------------------
function func_show_tail() {
echo -e "${LINE80}"
echo -e -n "${WALL_CHAR}"
echo -e "\tEND"
echo -e "${LINE80}"
}
# --------------------------------------------------------------------------------
# show os info
# --------------------------------------------------------------------------------
function func_show_os_info() {
local str_date=$(date +%Y_%m_%d_%H_%M_%S)
# show time
echo -e -n "${WALL_CHAR}"
echo -e "\t${str_date}"
# show shell
echo -e -n "${WALL_CHAR}"
echo -e "\t${SHELL}"
# show language
echo -e -n "${WALL_CHAR}"
echo -e "\t${LANG}"
# show user
echo -e -n "${WALL_CHAR}"
echo -e "\t${USER}"
echo -e "${LINE80}"
}
# --------------------------------------------------------------------------------
# show prog info
# --------------------------------------------------------------------------------
function func_show_prog_info() {
# show prog name
echo -e -n "${WALL_CHAR}"
echo -e "\t${PROG_NAME}"
# show prog version
echo -e -n "${WALL_CHAR}"
echo -e "\t${PROG_VER}"
# show code modify time
echo -e -n "${WALL_CHAR}"
echo -e "\t${PROG_TIME}"
echo -e "${LINE80}"
}
# --------------------------------------------------------------------------------
# @fn func_get_user_name_and_home_dir_for_one_row_from_etc_passwd
# @brief get usrname and homedir from one row from /etc/passwd
# @parameter $1, IN, row content
# @parameter g_user_name__func_get_user_name_and_home_dir_for_one_row_from_etc_passwd, OUPUT, user name
# @parameter g_home_dir__func_get_user_name_and_home_dir_for_one_row_from_etc_passwd, OUPUT, user home dir
# @return g_err_code_xx
# --------------------------------------------------------------------------------
g_user_name__func_get_user_name_and_home_dir_for_one_row_from_etc_passwd=""
g_home_dir__func_get_user_name_and_home_dir_for_one_row_from_etc_passwd=""
function func_get_user_name_and_home_dir_for_one_row_from_etc_passwd() {
local rc=$g_err_code_err
local str_field=""
local IFS_org=""
local pos=0
local b_was_get_user_name=false
local b_was_get_home_dir=false
IFS_org=$IFS
IFS=$':'
for str_field in $1
do
if [ $pos -eq $g_etc_passwd_row_field_index_user_name ]
then
b_was_get_user_name=true
g_user_name__func_get_user_name_and_home_dir_for_one_row_from_etc_passwd=$str_field
elif [ $pos -eq $g_etc_passwd_row_field_index_home_dir ]
then
b_was_get_home_dir=true
g_home_dir__func_get_user_name_and_home_dir_for_one_row_from_etc_passwd=$str_field
fi
pos=$(echo "scale=4; $pos + 1" | bc) # pos++
if [ "$b_was_get_home_dir" = true ] && [ "$b_was_get_home_dir" = true ]
then
rc=$g_err_code_ok
break
fi
done
IFS=$IFS_org
return $rc
}
# --------------------------------------------------------------------------------
# @fn func_is_user_exist
# @brief is user exist
# @parameter IN, username
# @prarmeter OUT, g_user_name__func_is_user_exist
# @prarmeter OUT, g_home_dir__func_is_user_exist
# @return g_err_code_xx
# --------------------------------------------------------------------------------
g_user_name__func_is_user_exist=""
g_home_dir__func_is_user_exist=""
function func_is_user_exist() {
local rc=$g_err_code_err
local rc_tmp=$g_err_code_err
local str_row_content=""
local IFS_org=""
local _str_tmp=""
local str_user_name=""
local str_user_home_exist_rv=""
local str_user_home=""
# clear my output parameter
g_user_name__func_is_user_exist=""
g_home_dir__func_is_user_exist=""
# user name
str_user_name=$1
# user home
str_user_home="/home/${str_user_name}"
IFS_org=$IFS
IFS=$'\n'
for str_row_content in $(cat "/etc/passwd")
do
func_get_user_name_and_home_dir_for_one_row_from_etc_passwd $str_row_content
rc_tmp=$?
if [ $rc_tmp -eq $g_err_code_err ]
then
continue
elif [ $str_user_name = $g_user_name__func_get_user_name_and_home_dir_for_one_row_from_etc_passwd ]
then
# ok : was get username and homedir
g_user_name__func_is_user_exist=$g_user_name__func_get_user_name_and_home_dir_for_one_row_from_etc_passwd
g_home_dir__func_is_user_exist=$g_home_dir__func_get_user_name_and_home_dir_for_one_row_from_etc_passwd
rc=$g_err_code_ok
break;
else
# echo "not process"
rc_tmp=$rc_tmp # do nothing
fi
done
IFS=$IFS_org
if [ $rc -eq $g_err_code_ok ]
then
# find user in /etc/passwd
return $rc
fi
g_user_name__func_is_user_exist=$str_user_name
# if user name not in /etc/passwd, try to find is the user have home dir ?
# before opt a file, please check is file exist. if file is dir, do check also
# do check can guard some error message on opt file
if ! [ -d $str_user_home ]
then
rc=${g_err_code_user_not_exist}
return $rc
fi
# ls -d xx # only list dir by give
str_user_home_exist_rv=$(ls -d $str_user_home > /dev/null) # e.g. return /home/root
rc=$? #e.g. return 0, 1, or other int value
# if dir not exist, rc = 2
# rc is number, cmpare use -eq
if [ 0 -eq $rc ]
then
g_home_dir__func_is_user_exist=${str_user_home}
rc=${g_err_code_user_not_exist_but_have_home_dir}
else
rc=${g_err_code_user_not_exist}
fi
return $rc
}
# --------------------------------------------------------------------------------
# fuc_show_user_info
# --------------------------------------------------------------------------------
function fuc_show_user_info() {
local rc=0
func_is_user_exist $1
rc=$?
if [ $rc -eq $g_err_code_ok ]
then
echo "user [$1] exist, user home dir = $g_home_dir__func_is_user_exist"
elif [ $rc -eq $g_err_code_user_not_exist_but_have_home_dir ]
then
echo "user [$1] not exist, but have home dir, user home dir = $g_home_dir__func_is_user_exist"
elif [ $rc -eq $g_err_code_user_not_exist ]
then
echo "user [$1] not exist"
else
echo "unknow return code, please contact admin"
fi
echo
}
# --------------------------------------------------------------------------------
# do task
# --------------------------------------------------------------------------------
function func_do_task() {
local rc=0
local str_user_name=""
local is_user_exist=0
# case user exist and have home dir
fuc_show_user_info "root"
# user not exist, but have home dir
fuc_show_user_info "dev"
# user not exist and have not home dir
fuc_show_user_info "user_not_exist"
}
# --------------------------------------------------------------------------------
# main shell script
# --------------------------------------------------------------------------------
func_init
func_show_title
func_show_prog_info
func_show_os_info
func_do_task
func_show_tail
func_uinit
总结
看技术书,到了自己感觉合适的节点,就有必要做个小实验,将细节的地方验证一次。
免得看后面时,被前面没有验证的知识点拖住后腿。
看着蛮简单的知识点组合,如果要验证下来,远多于看书的时间。这个实验写了一天半(编码和调试):)
书上讲的知识点可能和自己需要的沾边,但是又不完全是自己的需求时,完善实验程序和验证自己的想法显得比较紧迫。感觉如果带着需求来看书,效果确实比无需求来的明显. 等我看完这书,回头来再重写个安装程序的脚本,那就漂亮多了。
写脚本工程,代码写的风格一致,维护性好,显得比写C程序还重要。毕竟脚本不是强类型语言,如果写的不规矩,等出了问题,排bug很费时间。