Shell Script Template

#!/usr/bin/env bash
# leehom Chen clh021@gmail.com
# 本脚本旨在提供一个用于快速编写 shell 脚本模板
set -e

# 路径准备
OldPath=$(pwd)
# SCRIPT_PATH=$(realpath "${BASH_SOURCE[0]}")
SCRIPT_PATH=$(realpath "$0")
ProjectPath="$(dirname "$(dirname "$SCRIPT_PATH")")"

pushd $ProjectPath > /dev/null
if [ -f "$ProjectPath/.env" ]; then
  source "$ProjectPath/.env"
fi

# arch=`dpkg --print-architecture` # amd64
arch=$(uname -m) # x86_64
echo "当前系统架构为: $arch"
nowTime=$(date +%Y%m%d_%H%M%S)
pkgTime=$(git log -1 --format=%at | xargs -I{} date -d @{} +%Y%m%d_%H%M%S)
LITHIUM_BIN=

# 为适应不同打包环境(仅拷贝脚本等文件而非整个项目即可打包),本脚本会自动寻找浏览器程序进行容器打包
# 查找 lithium 程序
findLithiumBin() {
  if test -f "$ProjectPath/lithium/lithium"; then
      LITHIUM_BIN="$ProjectPath/lithium/lithium"
  elif test -f "$ProjectPath/../lithium/lithium"; then
      LITHIUM_BIN="$ProjectPath/../lithium/lithium"
  elif test -f "$ProjectPath/build/dist/lithium/lithium"; then
      LITHIUM_BIN="$ProjectPath/build/dist/lithium/lithium"
  elif test -f "$ProjectPath/../../lithium/lithium"; then
      LITHIUM_BIN="$ProjectPath/../../lithium/lithium"
  fi
}

generateSha512sumFile() {
  echo > SHA512SUMS
  for f in $1; do
    if [ -r $f ]; then
      echo "$(date +%Y-%m-%d_%H:%M:%S) $f"
      sha512sum "$f" >> SHA512SUMS
    else
      echo "Not find $1 files."
    fi
  done
}

display_usage() {
    echo -e "
example:
    $0 -b -u https://baidu.com
Usage:
    b build before test (default:false)
    a appid (default:12as.ji_a.com)
    u URL to open
    g Whether use gecko engine
    c Whether clear cache"
    # \t\n
    exit 1
}

# 解析传递的参数
_URL=
_CLEAR=
_BUILD=
_USE_GECKO=
_APPID=12as.ji_a.com

parseArg() {
  # check whether user had supplied -h or --help . If yes display usage
  if [[ ( $* == "--help") ||  $* == "-h" ]]; then
      display_usage
  fi
  while getopts "ba:u:cg" arg; do
    case $arg in
      b) _BUILD=true ;;
      a) _APPID=${OPTARG} ;;
      u) _URL=${OPTARG} ;;
      c) _CLEAR=true ;;
      g) _USE_GECKO=true ;;
      ?) display_usage ;;
    esac
  done
}

parseArg "$@"

showOptions() {
  echo "_URL: $_URL"
  echo "_CLEAR: $_CLEAR"
  echo "_BUILD: $_BUILD"
  echo "_USE_GECKO: $_USE_GECKO"
  echo "_APPID: $_APPID"
}

main() {
  findLithiumBin
  if test -n "$LITHIUM_BIN";then
    echo '找到了要打包的浏览器。'
    if [[ -n "$_CLEAR" ]]; then
      echo '正在清理缓存'
    fi
    if [[ -z "$_URL" ]]; then
      _URL="http://localhost:8000" # /gecko.html"
    fi
    echo '正在打开测试页面'
    export DEBUG_GECKO=true
    COMMAND="${PROJ_DIR}/build/dist/lithium/lithium ${_OPTIONS} ${_URL}"
    echo "$COMMAND";
    #strace -f -o "${PROJ_DIR}/tools/run-lithium-in-strace.log" \
    # $COMMAND | grep --color -E '^|JavaScript|error|x11ID|lastSet'
    cd -
  else
    echo '没有找到要打包的浏览器。'
  fi
}

showOptions


export LANG=en_US.UTF-8

./child.python &
PID_P1=$!
./detect &
PID_P2=$!
./main &
PID_P3=$!
./kit &
PID_P4=$!

on_exit() {
	echo "clean on_exit, kill $PID_P1 $PID_P2 $PID_P3 $PID_P4"
	kill -9 ${PID_P4} || :
	kill -9 ${PID_P3} || :
	kill -9 ${PID_P2} || :
	kill -9 ${PID_P1} || :
}

trap on_exit EXIT SIGTERM SIGINT

main

popd > /dev/null

cd "$OldPath"
.PHONY: init
init: .git/hooks/pre-push .air

.git/hooks/pre-push:makefile
	@echo "#!/usr/bin/env bash" > $@
	@echo "set -e" >> $@
	@echo "make test" >> $@
	@echo "cd web && npm run lint" >> $@
	@chmod a+x $@

.PHONY: clean
clean:
	rm -rf dist/webdist
	rm -rf web/dist
	rm -rf web/node_modules

.PHONY: test
test:
	sh -c "ulimit -n 20000; go test ./..."

#TODO: move to k8s or jenkins
upload-cos: 
	cd web && npm run build && cd dist && coscmd upload -rs . /

.PHONY: .air
.air:
	go get -u github.com/cosmtrek/air
	touch .air

.PHONY: dev
dev: p1="air"
dev: p2=["sh", "-c", "cd web && exec npm run serve"]
dev: .air test_data
	@echo 'import subprocess; [p.wait() for p in subprocess.Popen(${p1}),subprocess.Popen(${p2})]' | python2

.PHONY: test_data
test_data:
	mkdir test_data

为什么 echo 出来的命令在terminal中直接执行没问题,而在脚本中执行有问题呢? 因为 terminal 中直接执行可以读取到当前用户所有环境变量,而脚本中执行却不可以。

# 将输出的命令和脚本结果对比即可得到差异,(由公司产品无法切换中文输入法问题发现)
# 可以通过 sudo -E 的方式保持所有环境变量(如果没有保持的权限会报错)
SCRIPT_PATH=$(realpath "$0")
if [[ ${UID} -gt 0 ]] ; then
    sudo "${SCRIPT_PATH}"
    exit
fi
echo sudo -u "${SUDO_USER}" env
sudo -u "${SUDO_USER}" env

例子,是否可以切换中文输入法输入中文

# sudo apt install gedit
# 命令行中执行
sudo gedit # 不能
sudo -u chenlianghong gedit # 可以
# 脚本中执行
sudo -u "${SUDO_USER}" gedit # 不可以
sudo -E -u "${SUDO_USER}" gedit # 不可以,输入法相关的环境变量没有带过来
# 有关输入法的问题,经过几轮研究(不同软件和不同发行版测试),发现最好是直接模拟普通用户再来执行脚本,以完整获取环境变量

目前发现,不同发行版(可能还包含同样发行版的不同版本)对于环境变量的传递处理方式都不一样,所以目前只能当作是对产品运行环境的提前测试。