shell----自动补齐

谢弘阔
2023-12-01
用过bash的人,可能都对TAB自动补全功能有印象吧,按一下“TAB“键就自动帮你把命令或者文件名补全,确实好用。
这个应该是bash解析用户输入的时候,加上这个自动补全的功能的。方便的地方是bash提供的内置命令complete允许你对这个功能进行自定义扩展。 比如
complete -F _my_host my_ssh  就会指定 my_ssh这个名字的自动完成由 _my_host 这个函数去处理

比如我在 .bashrc 后面加上下面这个代码之后
----------------------------------------------
_my_host() {
    local HOST cur

    COMPREPLY=()
    _get_comp_words_by_ref cur

    HOST="local test test2 devolop"

    COMPREPLY=( $( compgen -W "$HOST" -- "$cur" ) )
}
complete -F _my_host my_ssh
alias egenera_ssh=/home/widebright/桌面/my_ssh.pl
-----------------------------------------------
这样设置之后,在终端再输入自己的自定义命令my_ssh 然后按TAB键,就会自动出来自己预先定义的host主机名字了
---------------
widebright@:~/桌面$ my_ssh 
local test test2 devolop
-------------------------

其中COMPREPLY 是Bash的内置变量,一个数组,返回结果到这里去后,bash就是读取这个变量作为自动完成的匹配组合的。
compgen -W "$HOST" -- "$cur" 命令根据当前的输入"$cur" 返回$HOST中匹配的部分。compgen也是内置命令的。_get_comp_words_by_ref 是预定义函数,不过自己从COMP_WORDS 和COMP_CWORD两个预定义变量中去读取当前输入信息。COMP_WORDS表示当前命令输入参数的单词数组,COMP_CWORD表示当前光标的 位置。参考一个例子

------------------------
_xm() 
{
    local cur prev opts base
    COMPREPLY=()
    cur="${COMP_WORDS[COMP_CWORD]}"
    prev="${COMP_WORDS[COMP_CWORD-1]}"

    #
    #  The basic options we'll complete.
    #
    opts="console create list"


    #
    #  Complete the arguments to some of the basic commands.
    #
    case "${prev}" in
    console)
        local running=$(for x in `xm list --long | grep name|grep−vDomain−0|awk′print$2′|tr−d`; do echo ${x} ; done )
        COMPREPLY=( $(compgen -W "${running}" -- ${cur}) )
            return 0
            ;;
        create)
        local names=$(for x in `ls -1 /etc/xen/*.cfg`; do echo ${x/\/etc\/xen\//} ; done )
        COMPREPLY=( $(compgen -W "${names}" -- ${cur}) )
            return 0
            ;;
        *)
        ;;
    esac

   COMPREPLY=($(compgen -W "${opts}" -- ${cur}))  
   return 0
}
complete -F _xm xm
------------------------------------

complete 命令的和预定义的详细说明可以参考bash的文档。
启动complete -p 可以查看bash已经定义的命令的自动完成函数。

pack.sh 的

#!/bin/bash

####set board
thisXwDevicePath="`echo $DEVICE`"
thisXwBoard=chiphd
XwLicheeConfig=

cp $DEVICE/wifi_efuse_8189e.map $OUT/system/etc/wifi/ && echo -e "cp wifi_efuse_8189e.map"

if [ -f $thisXwDevicePath/configs_chiphd/do_chiphd.sh ]; then
        NowCustomFlagFile=$thisXwDevicePath/configs_chiphd/NowCustom.sh
        if [ ! -f $NowCustomFlagFile ]; then
                bash $thisXwDevicePath/configs_chiphd/do_chiphd.sh
        fi
        NowCustomCfg=`sed -n '1p' $NowCustomFlagFile`
        thisXwBoard=$(echo $NowCustomCfg  | awk -F/ '{print $(NF-2)"-"$(NF-1)}')
        XwLicheeConfig=${NowCustomCfg%/*}/lichee
        #cat $DEVICE/configs_chiphd/custom/NowCustom.sh | awk -F/ '{print $(NF-2) "/" $(NF-1)}'`
fi

thisCfgDir=`echo $ANDROID_BUILD_TOP/../lichee/tools/pack/chips/*/configs/android`
## for a10
if [ ! -d "$thisCfgDir" ]; then thisCfgDir=`echo $ANDROID_BUILD_TOP/../lichee/tools/pack/chips/*/configs/crane`; fi
## for a3x-4.4
if [ ! -d "$thisCfgDir" ]; then thisCfgDir=`echo $ANDROID_BUILD_TOP/../lichee/tools/pack/chips/sun8iw5p1/configs`; fi

## copy .fex file
if [ "$XwLicheeConfig" -a -d "$XwLicheeConfig" ]; then
        #echo $thisCfgDir/$thisXwBoard
        if [ ! -d $thisCfgDir/$thisXwBoard ]; then mkdir $thisCfgDir/$thisXwBoard; fi
        cp -r --force ${XwLicheeConfig}/configs/*.* $thisCfgDir/$thisXwBoard/
        echo "done : cp -r --force ${XwLicheeConfig}/configs/*.* $thisCfgDir/$thisXwBoard/"
else
        echo "XwLicheeConfig = ${XwLicheeConfig}"
fi

#### repo tag file to system.img when $1 = --tag
XwImgAndroidTagFunc="$thisXwDevicePath/../zzzzz-chiphd/xw_img_create_android_tag.sh"
if [ -f $XwImgAndroidTagFunc ]; then
        $XwImgAndroidTagFunc $1
fi

#### prepare for rename-img-file
XwImgRenameFunc="$thisXwDevicePath/../zzzzz-chiphd/xw_img_rename.sh"
if [ -f $XwImgRenameFunc ]; then
        $XwImgRenameFunc --new && echo "auto rename img file later ..."
fi


CHIPHD_NEED_REBUILD_SYS_IMG=false

#wifi efuse
wifi_efuse_src=$thisXwDevicePath/configs_chiphd/wifi_efuse/wifi_efuse_8189e_for_MB1019Q5.map
wifi_efuse_dst=$OUT/system/etc/wifi/wifi_efuse_8189e.map
if [ ! -f $wifi_efuse_dst ]; then
        cp $wifi_efuse_src $wifi_efuse_dst && echo "Wifi Map: cp $wifi_efuse_src $wifi_efuse_dst"
        CHIPHD_NEED_REBUILD_SYS_IMG=true
fi

#### over-write build.prop
CHIPHD_OVERWRITE_BUILD_PROP_SH=$thisXwDevicePath/chiphd_overwrite_build_prop.sh
if [ -f "$CHIPHD_OVERWRITE_BUILD_PROP_SH" ]; then
        old_buildprop_sha1sum=$(sha1sum $OUT/system/build.prop | awk '{print $1}')
        bash $CHIPHD_OVERWRITE_BUILD_PROP_SH $OUT/system/build.prop
        new_buildprop_sha1sum=$(sha1sum $OUT/system/build.prop | awk '{print $1}')
        if [ "$old_buildprop_sha1sum" != "$new_buildprop_sha1sum" ]; then
                CHIPHD_NEED_REBUILD_SYS_IMG=true
        fi
fi

#### del apks
S_DelAPPSet=`echo Update.apk Home.apk YouTube.apk Chrome.apk Development.apk Gmail2.apk Hangouts.apk VideoEditor.apk Contacts.apk ChromeWithBrowser.apk OpenWnn.apk com.google.android.apps.maps_chiphd-0.apk Maps.apk`
if [ "$S_DelAPPSet" ]; then
        for f in $S_DelAPPSet
        do
                S_DelAPP=$OUT/system/app/$f
                if [ -f $S_DelAPP ]; then
                        rm $S_DelAPP && CHIPHD_NEED_REBUILD_SYS_IMG=true && echo "----del $S_DelAPP "
                fi
                S_DelAPP=$OUT/system/priv-app/$f
                if [ -f $S_DelAPP ]; then
                        rm $S_DelAPP && CHIPHD_NEED_REBUILD_SYS_IMG=true && echo "----del $S_DelAPP "
                      fi
        done
fi

#### rebuild system.img
if [ "$CHIPHD_NEED_REBUILD_SYS_IMG" = "true" ]; then
        echo "------------- rebuild system.img"
        make systemimage-nodeps
fi


#######################################################

#######################################################


cd $PACKAGE

chip=sun8iw5p1
platform=android
board=${thisXwBoard}
debug=uart0
sigmode=none

usage()
{
        printf "Usage: pack [-cCHIP] [-pPLATFORM] [-bBOARD] [-d] [-s] [-h]
        -c CHIP (default: $chip)
        -p PLATFORM (default: $platform)
        -b BOARD (default: $board)
        -d pack firmware with debug info output to card0
        -s pack firmware with signature
        -h print this help message
"
}

while getopts "c:p:b:dsh" arg
do
        case $arg in
                c)
                        chip=$OPTARG
                        ;;
                p)
                        platform=$OPTARG
                        ;;
                b)
                        board=$OPTARG
                        ;;
                d)
                        debug=card0
                        ;;
                s)
                        sigmode=sig
                        ;;
                h)
                        usage
                        exit 0
                        ;;
                ?)
                        exit 1
                        ;;
        esac
done

./pack -c $chip -p $platform -b $board -d $debug -s $sigmode


#### rename
if [ -f $XwImgRenameFunc ]; then
        $XwImgRenameFunc --rename $thisCfgDir/$thisXwBoard/sys_config.fex $1
fi

另外一个脚本:

#!/bin/bash
# filename: cli-test.sh

UPCASE=false
DATE=""

usage() {
    echo "USAGE:"
    echo "cli-test <options>"
    echo "    -h      : print help"
    echo "    -u      : print info upcase"
    echo "    -p <xxx>: print info"
    echo "    -d <xxx>: date in print info"
}

print() {
    if $UPCASE
    then
       echo -n $1 | tr a-z A-Z
    else
        echo -n $1
    fi

    if [ "$DATE" != "" ]
    then
        echo "   date: $DATE"
    else
        echo ""
    fi
}

while getopts "hup:d:" opt; do
    case "$opt" in
        h)
            usage
            exit 0
            ;;
        u)
            UPCASE=true
            ;;
        d)
            DATE=$OPTARG
            ;;
        p)
            print $OPTARG
            ;;
    esac
done

运行规则:

自定义补全

上面的补全是补全固定的参数,简单,但是用处也不大,用户记不住的其实就是那些会变的参数内容。 下面尝试动态补全 cli-test.sh 的参数 -d 的内容(内容是当前日期以及前3天和后三天的日期) 修改 bash_complete 脚本如下:

_complete_func() {
    local cur prev opts base
    COMPREPLY=()
    cur="${COMP_WORDS[COMP_CWORD]}"
    prev="${COMP_WORDS[COMP_CWORD-1]}"

    if [[ ${cur} == -* ]] ; then
        opts="-h -u -d -p"
        COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
    else
        opts=$( _complete_d_option )
        COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
    fi

    return 0
}

_complete_d_option() {
    date -v -3d +"%Y-%m-%d"
    date -v -2d +"%Y-%m-%d"
    date -v -1d +"%Y-%m-%d"
    date +"%Y-%m-%d"
    date -v +1d +"%Y-%m-%d"
    date -v +2d +"%Y-%m-%d"
    date -v +3d +"%Y-%m-%d"
}

complete -F _complete_func cli-test.sh

测试动态补全的效果

bash-3.2$ source bash_complete          # 使自动补全脚本生效
bash-3.2$ ./cli-test.sh -u -d 2016-10-1<TAB><TAB>   # 这是 2016-10-13 执行的结果,其他日子的结果会不一样
2016-10-10  2016-10-11  2016-10-12  2016-10-13  2016-10-14  2016-10-15  2016-10-16

上面就是动态补全,_complete_d_option 函数就是用来实现动态补全的。
 类似资料: