shell的GoodCoder的编写

来源:互联网 发布:golang defer func 编辑:程序博客网 时间:2024/04/19 09:46

runit是一个应用(application)启动管理工具。通过Procfile文件启动相应的进程。

1 试题描述

1.1 Procfile

Procfile 包含进程名字和启动进程的命令,用:分隔。如:

web: python -m SimpleHTTPServer $PORTdate: date $DATE_FORMATweb_2: while true ; do nc -l $PORT < index.html
  • 进程名字可以包含:字母, 数字, 下划线
  • Procfile中不可以写后台命令
  • runit将这些命令运行在后台
  • runit默认使用当前路径下的Procfile文件
  • 如果多次使用$PORT变量,则值递增。如第一个PORT的值是8080,则第二个PORT的值为8081,如果不在.env中设置PORT变量的值,则自动设置默认值为8080

1.2 环境变量

如果当前目录下存在.env文件,则从其中读取环境变量。这个文件由 键/值对 构成。如:

PORT=8080DATE_FORMAT='+%Y-%m-%d|%H:%M:%S'

1.3 程序执行

  • runit 启动Procfile中的所有进程
  • runit -f procfile -e env_file
  • runit -c 检查Procfile, env_file文件格式的正确性
  • runit -h 打印帮助

1.4 其他要求

  • Procfile和.env文件中可存在#注释
  • usage内容第一行如下, 其余内容自由发挥
Usage: runit [-c] [-f procfile|Procfile] [-e envfile|.env]
  • 日志打印到屏幕,格式如下,不同的进程的日志输出不同的颜色(web, date, web_2分别是不同的颜色)
11:39:45 web    | python -m SimpleHTTPServer 8080 started with pid 78111:39:45 date   | date +%Y-%m-%d|%H:%M:%S started with pid 79011:39:45 web_2  | nc -l 8081 < index.html started with pid 801
  • runit按照Procfile的描述启动进程,例如web就是启动一个前台进程(非后台进程或daemon)
  • runit可以接收SIGINT和SIGTERM信号,杀掉已启动的进程。确保runit在子进程运行结束后才退出。(如果进程可瞬间完成或是后台进程,则这个功能不起作用)
  • 除grep外不允许使用其他外部命令,如:sed, awk, ps, bc
  • 遵循shell编程规范

二、代码展示

#!/bin/bash##Copyright (c) 2016 Baidu.com,Inc. All Right Reserved##Author:panlu@baidu.com#Date:2016/08/17##Brief:#  process launcher#Globals:#  PORT COLOR_ARRAY#Arguments:#  -c check#  -f procfile#  -e envfile#  -h help#Returns:#  succ:0#  fail:1set -o pipefail# environmentSPORT=8080COLOR_ARRAY=('32' '33' '34' '35' '36')# variableprocfile=""envfile=""######################################Brief:#  usage#Globals:#  none#Agruments:#  none#Returns:#  none#####################################function usage() {    echo "Usage: runit [-c] [-f procfile|Procfile] [-e envfile|.env]             -c: check procfile and envfile             -f: load the procfile             -e: load the envfile             -h: help information             "}######################################Brief:#  verify the envfile#Globals:#  none#Agruments:#  envfile#Returns:#  succ:0#  fail:1#####################################function verify_env() {    local env_file="$1"    local ret_val=0    [[ ! -f "${env_file}" ]] && my_err "verify envfile not exists" && return 1    while read nextline; do        if echo "${nextline}" | grep -v "="; then            my_err "no_equal_mark"            continue        fi        key="${nextline%%=*}"        value="${nextline#*=}"        echo "${key}" | grep -q "[^a-zA-Z_]" && my_err "invalid_char" && ret_val=1        echo "${value}" | grep -qE "[[:space:]]" && my_err "value_have_space" && ret_val=1    done < <(grep -vE "^[[:space:]]*#" "${env_file}" | grep -v "^$")    return ${ret_val}}######################################Brief:#  verify the procfile#Globals:#  none#Agruments:#  procfile#Returns:#  succ:0#  fail:1#####################################function verify_proc() {    local proc_file="$1"    local ret_val=0    [[ ! -f "${proc_file}" ]] && my_err "verify procfile not exists" && return 1    while read nextline ; do        if echo "${nextline}" | grep -v ":"; then            my_err "no_colon_command"            continue        fi        key="${nextline%%:*}"        value="${nextline#*:}"        echo "${key}" | grep -q [^a-zA-Z_] && my_err "invalid_char" && ret_val=1    done < <(grep -vE "^[[:space:]]*#" "${proc_file}")    return ${ret_val}}######################################Brief:#  echo the error information#Globals:#  none#Agruments:#  errinfo#Returns:#  none#####################################function my_err() {    errinfo="$1"    echo "${errinfo}"}######################################Brief:#  echo the log information#Globals:#  COLOR_ARRAY #Agruments:#  proc_name command#Returns:#  succ:0#  fail:1#####################################function log() {    local name="$1"    local command="$2"    local color="$3"    cur_time=$(date +%H:%M:%s)    printf "\E[${color}m${cur_time} %-7s] | " "${name}"    tput sgr0    echo "${command}"    return 0}######################################Brief:#  execute the command#Globals:#  COLOR_ARRAY  PORT#Agruments:#  proc_name command#Returns:#  succ:0#  fail:1#####################################function run_command() {    local number="1"    local proc_name="$1"    local command="$2"    local cur_pid=$!    local cur_color="${COLOR_ARRAY[$number]}"    local comm_port=$(echo "${command}" | grep -e "\$PORT")    [[ -n "${comm_port}" ]] && [[ -z "${PORT}" ]] && PORT=8080    bash -c "${command}" > >(        while read result; do            log "${proc_name}" "${result}" "${COLOR}"        done    ) 2>&1 &    local output="$(eval echo \"${command}\")"    log "${proc_name}" "${output} start with pid ${cur_pid}" "${cur_color}"    [[ $? -ne 0 ]] && return 1    [[ -n "${comm_port}" ]] && PORT=$((${PORT} + 1))    (( number ++ ))    return 0}######################################Brief:#  load the env_file#Globals:#  none#Agruments:#  envfile#Returns:#  succ:0#  fail:1#####################################function load_env_file() {    set -a    local env_lists="$1"    for flag in $(echo "${env_lists}"); do        [[ -f "${flag}" ]] && source "${flag}"    done    return 0}######################################Brief:#  run procfile#Globals:#  none#Agruments:#  procfile#Returns:#  succ:0#  fail:1#####################################function run_procfile() {    local proc_file="$1"    [[ ! -f "${proc_file}" ]] && my_err "this procfile is not exists" && return 1    while read nextline; do        if echo "${nextline}" | grep -qv ":"; then            my_err "no_colon_command"            continue        fi        local key="${nextline%%:*}"        local value="${nextline#*:}"        [[ -n "${key}" ]] && [[ -n "${value}" ]] && run_command "${key}" "${value}"        [[ $? -ne 0 ]] && return 1    done < <(grep "" "${proc_file}" | grep -vE "[[:space:]]*#" | grep -v "^$" )    wait    return 0}######################################Brief:#  main procedure#Globals:#  procfile encfile#Agruments:#  none#Returns:#  none#####################################function main() {    local check=false    while getopts "f:e:ch" flag    do        case ${flag} in            c) check=true ;;            f) procfile="${OPTARG}" ;;            e) envfile="${OPTARG}" ;;            *) usage ;;        esac    done    if ${check}; then        if [[ -n "${procfile}" ]]; then            verify_proc "${procfile}"            PROC_RET_VALUE=$?            [[ ${PROC_RET_VALUE} -ne 0 ]] && exit 1        else            my_err "The procfile is null"            exit 1        fi        if [[ -z "${envfile}" ]];then            envfile="./.env"        fi        verify_env  "${envfile}"        ENV_RET_VALUE=$?        [[ ${ENV_RET_VALUE} -ne 0 ]] && exit 1    else        if [[ -z "${envfile}" ]]; then            envfile="./.env"        fi        load_env_file "${envfile}"        LOAD_ENV_RET_VALUE=$?        [[ ${LOAD_ENV_RET_VALUE} -ne 0 ]] && exit 1        if [[ -z "${procfile}" ]]; then            procfile="./Procfile"        fi        run_procfile "${procfile}"        RUN_RET_VALUE=$?        [[ RUN_RET_VALUE -ne 0 ]] && exit 1    fi    exit 0} main "$@"
0 0
原创粉丝点击