Shell Tips
简单的log和err_log
shell函数如下:
1 |
|
用法:
1 | log "hello world." |
输出:
1 | 2021-09-20 11:47:49 -- hello world. |
err_log要彩色输出
shell函数如下:
1 | function log() |
用法:
1 | log "hello world." |
输出:
1 | Black 0;30 Dark Gray 1;30 |
参考自: How to change the output color of echo in Linux
if else用法
用法:
1 | if [ expression1 ]; then |
switch case
用法:
1 | case 值 in |
其中;;相当于是break,*)相当于是default分支
一个解析参数的例子:
1 | while [ $# -gt 0 ] |
参考: 35.22. Handling Arguments with while and shift
创建临时文件
使用mktemp来创建临时文件,再使用trap在脚本运行结束后,删除该文件
mktemp用法: tmp_file=$(mktemp -p $TARGET_PATH tmp_file.XXXXXXXX) || exit 1
其中XXXXXXXX会自动变为一个随机字串。mktemp命令返回临时文件的路径。
例如:
1 | $ tmp_file=$(mktemp -p /tmp tmp_file.XXXXXXXX) || exit 1 |
再使用trap在shell脚本退出时,删除这个临时文件
1 | trap 'rm -rf "$tmp_file"' INT TERM EXIT |
合起来的使用方法:
1 | tmp_file=$(mktemp -p /tmp tmp_file.XXXXXXXX) || exit 1 |
信号量详解:
1 | $ trap -l |
常用的几个信号量:
| 信号名称 | 信号数 | 描述 |
|---|---|---|
| SIGHUP | 1 | 本信号在用户终端连接(正常或非正常)结束时发出,通常是在终端的控制进程结束时,通知同一session内的各个作业,这时它们与控制终端不再关联。登录Linux时,系统会分配给登录用户一个终端(Session)。在这个终端运行的所有程序,包括前台进程组和后台进程组,一般都属于这个Session。当用户退出Linux登录时,前台进程组和后台有对终端输出的进程将会收到SIGHUP信号。这个信号的默认操作为终止进程,因此前台进程组和后台有终端输出的进程就会中止。对于与终端脱离关系的守护进程,这个信号用于通知它重新读取配置文件。 |
| SIGINT | 2 | 程序终止(interrupt)信号,在用户键入 Ctrl+C 时发出。 |
| SIGQUIT | 3 | 和SIGINT类似,但由QUIT字符(通常是Ctrl /)来控制。进程在因收到SIGQUIT退出时会产生core文件,在这个意义上类似于一个程序错误信号。 |
| SIGFPE | 8 | 在发生致命的算术运算错误时发出。不仅包括浮点运算错误,还包括溢出及除数为0等其它所有的算术错误。 |
| SIGKILL | 9 | 用来立即结束程序的运行。本信号不能被阻塞,处理和忽略。 |
| SIGALRM | 14 | 时钟定时信号,计算的是实际的时间或时钟时间。alarm 函数使用该信号。 |
| SIGTERM | 15 | 程序结束(terminate)信号, 与SIGKILL不同的是该信号可以被阻塞和处理. 通常用来要求程序自己正常退出;kill 命令缺省产生这个信号。 |
参考:
创建文件夹锁
文件夹锁,防止脚本重复运行
1 | lockdir="${TARGET_PATH}/${LOCK_DIR}.lock" |
flock文件锁&后台运行程序
普通的flock文件锁机制在crontab中的运用
1 | * * * * * /usr/bin/flock -xn /tmp/crontab_task.lock -c "/bin/bash -l -c '/usr/local/bin/myshell.sh >> /tmp/xxxx.log 2>&1'" |
如果/usr/local/bin/myshell.sh中执行了后台运行的程序,比如nohup backgrounp.sh &,此时只要这个后台进程不结束,整个外层的/tmp/crontab_task.lock都不会被释放。
此时如果还是需要重复执行/usr/local/bin/myshell.sh的脚本,那么就不合适在外层使用flock来锁文件,可以考虑在脚本内部使用上面的文件夹锁的机制来实现。
ps检查某个进程是否存在
以ffmpeg为例。命令如下:
1 | exist=`ps aux | grep '/usr/local/bin/[f]fmpeg'` |
其中在ps命令中过滤grep本身的方法有两种
grep xxx后再grep -v grep, 如:ps aux | grep ffmpeg | grep -v grep- 给grep命令加上[], 例如:
ps aux | grep '/usr/local/bin/[f]fmpeg, 解释参见这边: Find and kill a process in one line using bash and regex
ps查找后杀进程
命令:
1 | ps -ef | grep your_process_name | grep -v grep | awk '{print $2}' | xargs kill |
shell切割字符串到array中
命令:
1 | IFS=', ' read -r -a array <<< "$string" |
IFS需要和read在一行中,这样保证只作用于当前的read命令。
获取单独的元素
1 | echo "${array[0]}" |
循环遍历数组中的元素:
1 | for element in "${array[@]}" |
同时获取索引和值
1 | for index in "${!array[@]}" |
获取数组中元素的数量:
1 | echo "${#array[@]}" |
参考: How to split a string into an array in Bash?
例子:
1 | $ string="字段1,字段2 字段3,字段4" |
如何将多分隔符的字串切割到array中
假设多分隔符字串为”|||”, 命令如下:
1 | mapfile -t array < <( echo "${line//|||/$'\n'}" ) |
先将|||更新为\n, 然后再map成array
参考: How to split string by string (multi-character) separator into an array?
逐行读取文件内容
命令:
1 | while IFS= read -r line; do |
参考: Read a file line by line assigning the value to a variable [duplicate]
将命令输出切割到数组中
Bash版本>=4:
1 | mapfile -t my_array < <( my_command ) |
Bash版本小于4:
1 | IFS=$'\n' read -r -d '' -a my_array < <( my_command && printf '\0' ) |