【问题标题】:Bash script checking command line parametersBash 脚本检查命令行参数
【发布时间】:2020-04-04 15:36:53
【问题描述】:

我仍在学习 bash、shell、Linux、regex 等。今天我分享这个我编写的 bash shell 脚本,我想在以后的脚本中用作“模块”。它彻底测试了一组命令行参数的有效性。我想向有经验的专家请教如何在语法、不同方法或替代命令方面更好地归档内容的建议和 cmets。我尝试了很多不同的方法,但我无法弄清楚。特别是我不喜欢“案例”结构。我宁愿定义一组选项字母,例如 'cmds=(h o g a m)',然后使用 'for c in "${cmds[@]}"; 循环遍历它。做'。但这导致了我必须使用动态变量名的问题,而我无法弄清楚。另一个问题是,我可以分配一个布尔值'true',但我不能用'a =!a'之类的东西来否定它。等等。任何建议都非常欢迎!

#!/bin/bash

# Usage: -p <path> -g <group> -o <owner> -m <mask> -h (help)

# Extensive option and parameter check:

expecting_option=true # alternatingly expecting option switch and parameter on command line

for i do # loop $i trough all parameters

    # display help:
    if [ $i = "-h" ]; then
        echo "Usage:"
        echo "-p <path> (default .)"
        echo "-o <owner>"
        echo "-g <group>"
        echo "-m <permission mask> (000 - 777)"
        exit
    fi;

    if [ "$expecting_option" = true ]; then # next arg supposed to be an option

        if [[ "$i" =~ ^(.)(.*?)(.*?)$ ]]; then # retrieve up to 3 single characters

            # Does it begin with '-' ?
            if [ ${BASH_REMATCH[1]} != "-" ]; then
                echo "ERROR: Option to begin with '-' expected at '"$i"'" >&2
                exit
            fi

            # only one letter length for options
            if [ -n "${BASH_REMATCH[3]}" ]; then
                echo "ERROR: Invalid option '"$i"'. Use -h for help" >&2
                exit
            fi

            switch=${BASH_REMATCH[2]} # save the current option switch

            # has this option already been set?
            # is option valid?
            case $switch in
                o)  if [ $o ]; then
                        echo 'ERROR: duplicate option: -o' >&2
                        exit
                    fi;;
                g)  if [ $g ]; then
                        echo 'ERROR: duplicate option: -g' >&2
                        exit
                    fi;;
                m)  if [ $m ]; then
                        echo 'ERROR: duplicate option: -m' >&2
                        exit
                    fi;;
                p)  if [ $p ]; then
                        echo 'ERROR: duplicate option: -p' >&2
                        exit
                    fi;;
                *)  echo "ERROR: Invalid option '"$i"'. Use -h for help" >&2
                    exit;;
            esac
        fi

        # next arg supposed to be the parameter
        expecting_option=!true # it's not true, so it works. But is it 'false'?

    else # this is supposed to be a parameter for the previous option switch

        if [[ "$i" =~ ^\- ]]; then # starts with '-' ?
            echo "ERROR: Parameter for "$switch" missing." >&2
            exit
        fi

        case $switch in
            o)  # check if designated owner exists (=0):
                if ! [ $(id -u "$i" > /dev/null 2>&1; echo $?) -eq 0 ]; then
                    echo "ERROR: user '"$i"' does not exist." >&2
                    exit
                fi
                o="$i";;
            g)  # check if designated group exists:
                if [ -z $(getent group "$i") ]; then
                    echo "ERROR: group '"$i"' does not exist." >&2
                    exit
                fi
                g="$i";;
            m)  if ! [[ $i =~ ^[0-7][0-7][0-7]$ ]]; then
                    echo "ERROR: Invalid right mask '"$i"'" >&2
                    exit
                fi
                m="$i";;
            p)  # check if path exists
                if ! [ -d "${i}" ]; then
                    echo "ERROR: Directory '"$i"' not found." >&2
                    exit
                fi
                p="$i";;
        esac

        expecting_option=true
    fi

done

# last arg must be a parameter:
if [ "$expecting_option" != true ]; then
    echo "ERROR: Parameter for "$switch" missing." >&2
    exit
fi

# at least o, g or m must be specified:

if ! [ $g ] && ! [ $o ] && ! [ $m ] ; then  
# this didn't work:  if ! [ [ $g ] || [ $o ] || [ $m ] ] ; then 
    echo "Nothing to do. Specify at least owner, group or mask. Use -h for help."
    exit
fi

# defaults: path = . owner = no change  group = no change  mask = no change
# set defaults:
[[ -z $p ]] && p="."

# All necessary options are given and checked:
# p defaults to . otherwise valid path
# if o is given, than the user exists
# if g is given, than the group exists
# if m is given, than the mask is valid
# at least one of o,g or m are given
# no option dupes
# no missing parameters

# ok, now let's do something:

# set group:owner + mask of whole directory tree:
if  [ $g ] || [ $o ] ; then
    [[ -n $g ]] && g=":"$g # use chown's column only if group change required, with or without owner
    sudo find $p -type f -exec chown $o$g {} + &&
    sudo find $p -type d -exec chown $o$g {} + 
fi
if [ $m ]; then
    sudo find $p -type f -exec chmod $m {} + &&
    sudo find $p -type d -exec chmod $m {} +
fi

【问题讨论】:

  • 阅读getopts 内置外壳以避免重新发明轮子。
  • 没听说过,谢谢

标签: regex linux bash shell


【解决方案1】:

使用“getopts”,正如@Shawn 在评论中所建议的那样,解析将变为:

# Default values for options
g=
o=
P=.
m=
while getopts g:o:p:m: opt ; do
    case "$opt" in
        g) g=$OPTARG ;;
        o) o=$OPTARG ;;
        p) p=$OPTARG ;;
        m) m=$OPTARG ;;
        # Abort on illgal option
        *) exit 2 ;;
    esac
done
shift $((OPTIND-1))

# Rest of code goes here

【讨论】:

    猜你喜欢
    • 2015-05-05
    • 1970-01-01
    • 2017-12-29
    • 1970-01-01
    • 2014-06-28
    • 2011-10-16
    • 1970-01-01
    • 2023-01-18
    • 2014-04-04
    相关资源
    最近更新 更多