#!/usr/bin/env bash #------------------------------------------------- # 工具包主脚本 # @author yeahoo2000@gmail.com #------------------------------------------------- # 检测是否在cygwin环境中 in_cygwin(){ local os=$(uname) [[ "${os:0:3}" == "CYG" ]]; return $? } # 检测某个函数是否已经定义 is_fun_exists(){ declare -F "$1" > /dev/null; return $? } # 检测某个命令是否存在 is_command_exists(){ command -v $1 >/dev/null; return $? } # 检测某个screen session是否存在 # 注意此函数不是绝对可靠,有可能会找出名称相似的screen session is_screen_exists(){ [[ $(screen -ls | grep "$1" | wc -l ) -gt 0 ]] ; return $? } # 判定是否为整数 is_integer(){ local re='^[0-9]+$' [[ $1 =~ $re ]]; return $? } # 检查数组中是否存在某个元素 # 参数1:数组 # 参数2: 元素 # 使用示例: in_array elems[@] $elem in_array(){ declare -a haystack=("${!1}") local needle=${2} for v in ${haystack[@]}; do if [[ ${v} == ${needle} ]]; then return 0 fi done return 1 } # 判断是否为空值 空值则要求输入 check_empty(){ if [ "$2" == "" ]; then read -p $1 input echo $input fi echo $2 } # 检查当前运行环境中是否存在tty has_tty(){ [[ -t 1 ]]; return $? } # 检查是否已经安装UnityEditor check_unity_editor(){ if [[ ! -f ${UNITY} ]]; then ERR "UnityEditor似乎未安装,请先安装或是编辑cfg.ini文件中的'UNITY'项,指定正确的路径" exit 1 fi } # 获取sql语句执行结果中的第一行 # 返回的结果存放在$row变量中 # 用法示例: # eval "$(mysql_get_row select * from mysql.user)" # for k in ${!row[@]}; do # echo $k = ${row[$k]} # done mysql_get_row(){ #set names utf8; local sql="$@ limit 1 " local lines=( $(mysql -h$OMS_DB_HOST -P$OMS_DB_PORT -u$OMS_DB_USER -p$OMS_DB_PASS -ss -D${OMS_DB_NAME} -e"$sql\G") ) lines=( ${lines[*]//\**/} ) # 删除分隔符 lines=( ${lines[*]//:\ /\'\]=\"} ) # 替换等号 lines=( ${lines[*]/#/tmp\[\'} ) # 替换变量名 lines=( ${lines[*]/%/\"} ) # 增加尾部双引号 declare -A tmp row eval "$(echo "${lines[*]}")" # 转成关联数组 # 去除多余空格 for k in ${!tmp[@]}; do row[${k/#* /}]=${tmp[$k]} done declare -p row } # 输出一条普通信息 INFO(){ echo -e "\e[92m=>\e[0;0m ${1}" } # 输出一条错误信息 ERR(){ >&2 echo -e "\e[91m>>\e[0;0m ${1}" } # ini文件解析 ini_parser(){ IFS=$'\n' && local ini=( $(<$1) ) # convert to line-array ini=( ${ini[*]//;*/} ) # remove comments ini=( ${ini[*]/#[/\}$'\n'ini_section_} ) # set section prefix ini=( ${ini[*]/%]/ \(} ) # convert text2function (1) ini=( ${ini[*]/=/=\( } ) # convert item to array ini=( ${ini[*]/%/ \)} ) # close array parenthesis ini=( ${ini[*]/%\( \)/\(\) \{} ) # convert text2function (2) ini=( ${ini[*]/%\} \)/\}} ) # remove extra parenthesis ini[0]='' # remove first element ini[${#ini[*]} + 1]='}' # add the last brace eval "$(echo "${ini[*]}")" # eval the result } # 获取脚本文件所在绝对路径(自动跟踪符号链接) get_real_path(){ local source="${BASH_SOURCE[0]}" while [ -h "$source" ]; do local dir="$( cd -P "$( dirname "$source" )" && pwd )" source="$( readlink "$source" )" [[ $source != /* ]] && source="$dir/$source" done echo "$( cd -P "$( dirname "$source" )/.." && pwd )" } # 检查锁 lock_check(){ local task=$1 local msg="$2==$ROOT" lock=/tmp/dldl_tools_${task}.lock if [ -f $lock ]; then taskname=$(<$lock) ERR "正在执行\"$taskname\"($task)任务,需等待该任务完成..." INFO "如需强行解锁(确保无人操作),请手动删除文件:$lock" exit 1 fi touch $lock # 加锁ls echo $msg > $lock } # 解锁 lock_release(){ local task=$1 lock=/tmp/dldl_tools_${task}.lock rm -f $lock } ## 多子进程控制 fun_wait_pro(){ pro_max=$1 while [ $(jobs -l | wc -l) -ge $pro_max ]; do sleep 0.2 done } # 时间 fun_time(){ echo $(date +">>##[%Y-%m-%d %H:%M:%S]") } # 提示是否继续 fun_alert(){ if [ "$alert_skip" != "" ]; then return fi echo "$1是否继续(y/n)" read ret case $ret in y|y|yes|yes) ;; *) exit 0 ;; esac } # 帮助输出 fun_help(){ for k in ${!DOC[@]}; do if [[ $k != *$1* ]]; then unset DOC[$k] fi done while [ ${#DOC[@]} -ne 0 ]; do mink='' for k in ${!DOC[@]}; do if [ "$mink" = "" ] || [[ "$mink" > "$k" ]]; then mink=$k fi done >&2 echo -e -n "\e[95m${mink}\e[0;0m" eval "printf ' %.0s' {1..$((26 - ${#mink}))}" >&2 echo -e "${DOC[$mink]}" unset DOC[$mink] done } # 调用函数 _CALL_FUNCTION(){ local fname="fun" for arg in $@; do fname="${fname}_${arg}" shift if is_fun_exists ${fname}; then ${fname} $@ exit 0 fi done ERR "无效的指令,请使用以下指令" fun_help } # 输出命令行补全信息 fun_completion(){ echo $(declare -p DOC) } # --- 执行入口 ----------------------------------------------------- ROOT=$(get_real_path) declare -A DOC ZONE_BASE=${ROOT}/zone # 默认服务器节点安装位置,cfg.ini中的配置会覆盖此项 # 检测并加载配置文件 if [ -f $ROOT/tools/cfg.ini ]; then ini_parser "${ROOT}/tools/cfg.ini" # ini_section_default # 选择使用default段的配置内容 fi # 载入子仓库中的工具脚本 scripts=("tools/tools.sh" "client/cli.sh" "server/srv.sh" "server_core/srv.sh" "tools/gen_data/gen_data.sh" "tools/gen_data/web_gen_data.sh" "client_core/pack.sh" "client_pack/pack.sh" "tools/lang/lang.sh" "client_h5/cli.sh" "client_core_h5/cli.sh" "client_android/pack.sh" "server_core_mod/srv.sh" "server_core_data/srv.sh") for f in ${scripts[@]}; do if [ ! -f ${ROOT}/${f} ]; then #echo "=======$f" continue fi source ${ROOT}/${f} done # 根据参数调用相应命令 _CALL_FUNCTION $@