前言:
通过对spark集群脚本的研读, 对一些重要的shell脚本技巧, 做下笔记.
*). 取当前脚本的目录
sbin=`dirname "$0"`
sbin=`cd "$sbin"; pwd`
代码评注:# 以上代码为获取执行脚本所在的目录的常用技巧# sbin=$(dirname $0) 返回可能是相对路径, 比如./ # sbin=$(cd $sbin; pwd) 采用pwd, 来返回脚本所在目录的绝对路径
*). 循环遍历脚本参数
while (( "$#" )); do
case $1 in
--with-tachyon)
TACHYON_STR="--with-tachyon"
;;
esac
shift
done
代码评注:# 这是段遍历脚本参数的常见代码片段# shell脚本中$#表示参数个数# 由于$0是脚本名称本身占据, 因此脚本对参数的遍历从$1开始, 借助shift变量左移, 方便了对变长参数列表的遍历# 基于事件的xml解析方式, 当采用pull方式去遍历的时候, 差不多也是类似的代码结构# 当然需要注意, shift处理参数变量之后, 对后续脚本代码处理变量是有影响的(负作用), 因此最佳实践是集中处理脚本参数
*). 引入配置脚本
. "$sbin/spark-config.sh"
代码评注:# shell脚本中'.' 等同于source, 把调用脚本作为调用方脚本的自身的一部分执行, source
*). 默认参数处理
if [ "$SPARK_MASTER_PORT" = "" ]; then
SPARK_MASTER_PORT=7077
fi
代码评注:# 对变量默认值的处理方式# 注意对变量添加"", if [ $SPARK_MASTER_PORT = "" ] 会报错误: "[: =: unary operator expected"# 类似的代码可采用-z $SPARK_MASTER_PORT的方式
if [ -z $SPARK_MASTER_PORT ]; then
SPARK_MASTER_PORT=7077
fi
*) 对变量的高级处理
this="${BASH_SOURCE-$0}"
代码评注:# ${BASH_SOURCE-$0}, 属于特殊用法, 用于获取脚本名称, 那为何不用$(basename $0), 如脚本注释里谈到了, 遇到软接连, $(basename $0)就不行了# 其次${BASH_SOURCE-$0}, 它属于${VAR_NAME:-DEFAULT_VALUE}这种变量语法的简写# 比如, ${name:-"lilei"}, 如果name没有定义, 则默认返回为"lilei", 若name定义了, 则返回${name}值
*) 对软链接的处理
# resolve links - $0 may be a softlink
common_bin=$(cd -P -- "$(dirname -- "$this")" && pwd -P)
script="$(basename -- "$this")"
代码评注:# 无论是"cd -P", 还是"pwd -P", -P参数表明若遇到soft link, 则取soft link对应的真实目录/文件
*) set -a/a的使用
set -a
. "${use_conf_dir}/spark-env.sh"
set +a
代码评注:# set -a, 把执行的变量自动export, set +a, 则把关闭该功能# 可以简单理解为, 把脚本的本地变量, 都默认添加了export修饰
*). $!的使用和pid文件的使用
nohup nice -n $SPARK_NICENESS "$SPARK_PREFIX"/bin/spark-class $command "$@" \
>> "$log" 2>&1 < /dev/null &
newpid=$!
echo $newpid > $pid
代码评注:# nohup 表示进程脱离session运行# nice -n 用于调整进程nice值# 2>&1 表示把标准错误(stderr, 2)关联到标准输出(stdout, 1), 可以简写为 &># $!表示上一个shell命令(后台运行)的pid# echo $newpid > $pid (代表文件), 是把进程pid写入到进程的pid文件中去# 很多服务(比如apache)会选择把自身的pid(进程id)写入到pid文件中去, 至于为何这么做? 各有各的应用场景, 下面的kill -0就应用到了
*). kill -0 的使用, 检测进程是否存在, 重入(误判)问题
if [ -f $pid ]; then
if kill -0 `cat $pid` > /dev/null 2>&1; then
echo $command running as process `cat $pid`. Stop it first.
exit 1
fi
fi
代码评注:# kill -0
*). 并发+wait使用
for slave in `cat "$HOSTLIST"|sed "s/#.*$//;/^$/d"`; do
ssh $SPARK_SSH_OPTS $slave $"${@// /\\ }" \
2>&1 | sed "s/^/$slave: /" &
if [ "$SPARK_SLAVE_SLEEP" != "" ]; then
sleep $SPARK_SLAVE_SLEEP
fi
done
wait
代码评注:# shell脚本没有多线程的概念, 且默认执行子shell是阻塞的, 因此只能通过后台运行多个子进程来模拟 # ssh $slave "
*). sed命令使用
sed "s/#.*$//;/^$/d"
sed "s/^/$slave: /"
代码评注:# 使用流编辑器sed, 对文本内容进行替换和删除, 赞sed