linux shell script : check user exist

前言

要写一个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很费时间。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值