Shell 脚本(shell script),是一种为 shell 编写的脚本程序。 业界所说的 shell 通常都是指 shell 脚本,但读者朋友要知道,shell 和 shell script 是两个不同的概念。 由于习惯的原因,简洁起见,本文出现的 “shell编程” 都是指 shell 脚本编程,不是指开发 shell 自身。
以上内容来源于runoob
上半年花了一个多月时间修改一个开源的BI项目(Redash ),改完后,由于没有使用也就暂时告一段落,就在昨天,一个客户说想找一个开源的BI系统,我们就给他推荐这个工具,因为它简单、方便、快捷,而且也比较受欢迎。但是客户对Docker不熟悉,就给他大致的讲了一个怎么在 Windows搭建一个测试环境。后来,突然想看看Redash的Dockerfile文件,看到里面的执行文件:
1 2 ENTRYPOINT ["/app/bin/docker-entrypoint"] CMD ["server"]
docker-entrypoint是一个shell脚本,但是因为自己对shell的使用还未入门,所以就着这个机会,去简单了解一下。我们先看一下docker-entrypoint中的代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 #!/bin/bash set -e celery_worker() { WORKERS_COUNT=${WORKERS_COUNT:-2} QUEUES=${QUEUES:-queries,scheduled_queries} WORKER_EXTRA_OPTIONS=${WORKER_EXTRA_OPTIONS:-} echo "Starting $WORKERS_COUNT workers for queues: $QUEUES..." exec /usr/local/bin/celery worker --app=redash.worker -c$WORKERS_COUNT -Q$QUEUES -linfo --max-tasks-per-child=10 -Ofair $WORKER_EXTRA_OPTIONS } scheduler() { echo "Starting RQ scheduler..." exec /app/manage.py rq scheduler } dev_scheduler() { echo "Starting dev RQ scheduler..." exec watchmedo auto-restart --directory=./redash/ --pattern=*.py --recursive -- ./manage.py rq scheduler } worker() { echo "Starting RQ worker..." exec /app/manage.py rq worker $QUEUES } dev_worker() { echo "Starting dev RQ worker..." exec watchmedo auto-restart --directory=./redash/ --pattern=*.py --recursive -- ./manage.py rq worker $QUEUES } dev_celery_worker() { WORKERS_COUNT=${WORKERS_COUNT:-2} QUEUES=${QUEUES:-queries,scheduled_queries} echo "Starting $WORKERS_COUNT workers for queues: $QUEUES..." exec watchmedo auto-restart --directory=./redash/ --pattern=*.py --recursive -- /usr/local/bin/celery worker --app=redash.worker -c$WORKERS_COUNT -Q$QUEUES -linfo --max-tasks-per-child=10 -Ofair } server() { # Recycle gunicorn workers every n-th request. See http://docs.gunicorn.org/en/stable/settings.html#max-requests for more details. MAX_REQUESTS=${MAX_REQUESTS:-1000} MAX_REQUESTS_JITTER=${MAX_REQUESTS_JITTER:-100} exec /usr/local/bin/gunicorn -b 0.0.0.0:5000 --name redash -w${REDASH_WEB_WORKERS:-4} redash.wsgi:app --max-requests $MAX_REQUESTS --max-requests-jitter $MAX_REQUESTS_JITTER } create_db() { exec /app/manage.py database create_tables } celery_healthcheck() { exec /usr/local/bin/celery inspect ping --app=redash.worker -d celery@$HOSTNAME } rq_healthcheck() { exec /app/manage.py rq healthcheck } help() { echo "Redash Docker." echo "" echo "Usage:" echo "" echo "server -- start Redash server (with gunicorn)" echo "celery_worker -- start Celery worker" echo "dev_celery_worker -- start Celery worker process which picks up code changes and reloads" echo "worker -- start a single RQ worker" echo "dev_worker -- start a single RQ worker with code reloading" echo "scheduler -- start an rq-scheduler instance" echo "dev_scheduler -- start an rq-scheduler instance with code reloading" echo "celery_healthcheck -- runs a Celery healthcheck. Useful for Docker's HEALTHCHECK mechanism." echo "rq_healthcheck -- runs a RQ healthcheck that verifies that all local workers are active. Useful for Docker's HEALTHCHECK mechanism." echo "" echo "shell -- open shell" echo "dev_server -- start Flask development server with debugger and auto reload" echo "debug -- start Flask development server with remote debugger via ptvsd" echo "create_db -- create database tables" echo "manage -- CLI to manage redash" echo "tests -- run tests" } tests() { export REDASH_DATABASE_URL="postgresql://postgres@postgres/tests" if [ $# -eq 0 ]; then TEST_ARGS=tests/ else TEST_ARGS=$@ fi exec pytest $TEST_ARGS } case "$1" in worker) shift worker ;; server) shift server ;; scheduler) shift scheduler ;; dev_scheduler) shift dev_scheduler ;; celery_worker) shift celery_worker ;; dev_celery_worker) shift dev_celery_worker ;; dev_worker) shift dev_worker ;; rq_healthcheck) shift rq_healthcheck ;; celery_healthcheck) shift celery_healthcheck ;; dev_server) export FLASK_DEBUG=1 exec /app/manage.py runserver --debugger --reload -h 0.0.0.0 ;; debug) export FLASK_DEBUG=1 export REMOTE_DEBUG=1 exec /app/manage.py runserver --debugger --no-reload -h 0.0.0.0 ;; shell) exec /app/manage.py shell ;; create_db) create_db ;; manage) shift exec /app/manage.py $* ;; tests) shift tests $@ ;; help) shift help ;; *) exec "$@" ;; esac
#!/bin/bash的作用 我们可以再很多sh脚本里面看到#!/bin/bash这段代码,那么它有什么作用呢?shell是一种脚本命令语言,它有多种解析器,例如:/bin/csh、/bin/perl、/bin/bash、bin/sh等等,那么在在第一行加上#!/bin/bash,就是告诉系统这个脚本需要bin/bash解释器来执行。
set -e的作用 set -e的作用是:当命令的返回值为非零状态时,则立即退出脚本的执行,防止导致一个致命的错误,而这些错误本应该在之前就被处理掉。 set -e 命令用法总结如下:
当命令的返回值为非零状态时,则立即退出脚本的执行。
作用范围只限于脚本执行的当前进行,不作用于其创建的子进程(https://blog.csdn.net/fc34235/article/details/76598448 )。
另外,当想根据命令执行的返回值,输出对应的log时,最好不要采用set -e选项,而是通过配合exit 命令来达到输出log并退出执行的目的。shell 中的 set -e 和 set +e的区别
shell 函数 shell函数的定义格式如下:
1 2 3 4 5 [ function ] funname [()] { action; [return int;] }
函数定义可以带function funname() 定义,也可以直接funname() 定义,不带任何参数。函数返回值可加return也可以不加,不加则以最后一条命令运行结果作为返回值。
1 2 3 4 5 6 7 8 celery_worker() { WORKERS_COUNT=${WORKERS_COUNT:-2} QUEUES=${QUEUES:-queries,scheduled_queries} WORKER_EXTRA_OPTIONS=${WORKER_EXTRA_OPTIONS:-} echo "Starting $WORKERS_COUNT workers for queues: $QUEUES..." exec /usr/local/bin/celery worker --app=redash.worker -c$WORKERS_COUNT -Q$QUEUES -linfo --max-tasks-per-child=10 -Ofair $WORKER_EXTRA_OPTIONS }
shell变量 1 2 # 如果WORKERS_COUNT未定义或者为空字符串,则返回默认值,否则返回WORKERS_COUNT的值 WORKERS_COUNT=${WORKERS_COUNT:-2}
注意,变量名和等号之间不能有空格,而且还需要遵循如下规则:
命名只能使用英文字母,数字和下划线,首个字符不能以数字开头。
中间不能有空格,可以使用下划线(_)。
不能使用标点符号。
不能使用bash里的关键字(可用help命令查看保留关键字)。
使用一个定义过的变量,只要在变量名前面加美元符号即可。例如:
1 $WORKERS_COUNT或者${WORKERS_COUNT}
shell 参数 我们可以在执行 Shell 脚本时,向脚本传递参数,脚本内获取参数的格式为:$n, n 代表一个数字,1 为执行脚本的第一个参数,2 为执行脚本的第二个参数,以此类推 实例 以下实例我们向脚本传递三个参数,并分别输出,其中 $0 为执行的文件名:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 #!/bin/bash # author:菜鸟教程 # url:www.runoob.com echo "Shell 传递参数实例!"; echo "执行的文件名:$0"; echo "第一个参数为:$1"; echo "第二个参数为:$2"; echo "第三个参数为:$3"; 为脚本设置可执行权限,并执行脚本,输出结果如下所示: $ chmod +x test.sh $ ./test.sh 1 2 3 Shell 传递参数实例! 执行的文件名:./test.sh 第一个参数为:1 第二个参数为:2 第三个参数为:3
1 2 3 4 5 6 7 8 9 $# 传递到脚本的参数个数 $* 以一个单字符串显示所有向脚本传递的参数。 如"$*"用「"」括起来的情况、以"$1 $2 … $n"的形式输出所有参数。 $$ 脚本运行的当前进程ID号 $! 后台运行的最后一个进程的ID号 $@ 与$*相同,但是使用时加引号,并在引号中返回每个参数。 如"$@"用「"」括起来的情况、以"$1" "$2" … "$n" 的形式输出所有参数。 $- 显示Shell使用的当前选项,与set命令功能相同。 $? 显示最后命令的退出状态。0表示没有错误,其他任何值表明有错误。
这里直接copy runoob 的内容
shell case 用法 1 2 3 4 5 6 7 8 9 10 11 12 13 case "$1" in worker) shift worker ;; help) shift help ;; *) exec "$@" ;; esac
shift命令:在shell中,经常可能会遇到多参数传递,例如$1,$2,…$9,借助shift命令可以访问更多传递的参数 case语句:
以case开头,esac结尾;
取值后面必须为单词in
匹配一个值与一个模式以”)”(右括号)结束
双分号 “;;” 表示命令序列结束;
默认模式使用”*)”表示,在不满足前面的模式后,执行默认模式后的命令 示例:1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 worker() { WORKERS_COUNT=${WORKERS_COUNT:-2} QUEUES=${QUEUES:-queries,scheduled_queries} WORKER_EXTRA_OPTIONS=${WORKER_EXTRA_OPTIONS:-} echo "Starting $WORKERS_COUNT workers for queues: $QUEUES..." echo "$WORKERS_COUNT" } help() { echo "Redash Docker." echo "" echo "Usage:" echo "" echo "server -- start Redash server (with gunicorn)" echo "celery_worker -- start Celery worker" echo "dev_celery_worker -- start Celery worker process which picks up code changes and reloads" echo "worker -- start a single RQ worker" echo "dev_worker -- start a single RQ worker with code reloading" echo "scheduler -- start an rq-scheduler instance" echo "dev_scheduler -- start an rq-scheduler instance with code reloading" echo "celery_healthcheck -- runs a Celery healthcheck. Useful for Docker's HEALTHCHECK mechanism." echo "rq_healthcheck -- runs a RQ healthcheck that verifies that all local workers are active. Useful for Docker's HEALTHCHECK mechanism." echo "" echo "shell -- open shell" echo "dev_server -- start Flask development server with debugger and auto reload" echo "debug -- start Flask development server with remote debugger via ptvsd" echo "create_db -- create database tables" echo "manage -- CLI to manage redash" echo "tests -- run tests" } case "$1" in worker) shift worker ;; help) shift help ;; *) exec "$@" ;; esac
效果如下:1 2 3 [root@VM_175_142_centos ~]# ./shell_echo.sh worker Starting 2 workers for queues: queries,scheduled_queries... 2
结束 这里只是借助redash的sh脚本来简单了解了一下shell的一些常用命令及语法,当然,shell的强大之处肯定不止于此,后面再遇到的时候,再来学习。大家也可以去runoob 系统的学习一下