简单的log和err_log
shell函数如下:
1 2 3 4 5 6 7 8 9 10 11
| function log() { timer=`date "+%Y-%m-%d %H:%M:%S"` echo "$timer -- $1" } function err_log() { log "[Error]: $1" }
|
用法:
1 2
| log "hello world." err_log "hello error."
|
输出:
1 2
| 2021-09-20 11:47:49 -- hello world. 2021-09-20 11:47:49 -- [Error]: hello error.
|
err_log要彩色输出
shell函数如下:
1 2 3 4 5 6 7 8 9 10 11 12
| function log() { timer=`date "+%Y-%m-%d %H:%M:%S"` echo -e "$timer -- $1" } function err_log() { RED='\033[0;31m' NC='\033[0m' # No Color log "${RED}[Error]: $1 ${NC}" }
|
用法:
1 2
| log "hello world." err_log "hello color error."
|
输出:

附带 ANSI escape codes
1 2 3 4 5 6 7 8
| Black 0;30 Dark Gray 1;30 Red 0;31 Light Red 1;31 Green 0;32 Light Green 1;32 Brown/Orange 0;33 Yellow 1;33 Blue 0;34 Light Blue 1;34 Purple 0;35 Light Purple 1;35 Cyan 0;36 Light Cyan 1;36 Light Gray 0;37 White 1;37
|
参考自: How to change the output color of echo in Linux
if else用法
用法:
1 2 3 4 5 6 7 8 9
| if [ expression1 ]; then statement1 statement2 elif [ expression2 ]; then statement3 statement4 else statement5 fi
|
switch case
用法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| case 值 in 模式1) command1 command2 command3 ;; 模式2) command1 command2 command3 ;; *) command1 command2 command3 ;; esac
|
其中;;
相当于是break,*)
相当于是default分支
一个解析参数的例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| while [ $# -gt 0 ] do case "$1" in -a) options="$options $1" # 没有参数只有-a ;; -f) options="$options $1" # -f file_name形式 argfile="$1" shift ;; *) files="$files $1" ;; esac shift done
|
参考: 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 2 3 4
| $ tmp_file=$(mktemp -p /tmp tmp_file.XXXXXXXX) || exit 1 $ echo $tmp_file /tmp/tmp_file.psCxkVau $
|
再使用trap
在shell脚本退出时,删除这个临时文件
1
| trap 'rm -rf "$tmp_file"' INT TERM EXIT
|
合起来的使用方法:
1 2
| tmp_file=$(mktemp -p /tmp tmp_file.XXXXXXXX) || exit 1 trap 'rm -rf "$tmp_file"' INT TERM EXIT
|
信号量详解:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| $ trap -l 1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL 5) SIGTRAP 6) SIGABRT 7) SIGBUS 8) SIGFPE 9) SIGKILL 10) SIGUSR1 11) SIGSEGV 12) SIGUSR2 13) SIGPIPE 14) SIGALRM 15) SIGTERM 16) SIGSTKFLT 17) SIGCHLD 18) SIGCONT 19) SIGSTOP 20) SIGTSTP 21) SIGTTIN 22) SIGTTOU 23) SIGURG 24) SIGXCPU 25) SIGXFSZ 26) SIGVTALRM 27) SIGPROF 28) SIGWINCH 29) SIGIO 30) SIGPWR 31) SIGSYS 34) SIGRTMIN 35) SIGRTMIN+1 36) SIGRTMIN+2 37) SIGRTMIN+3 38) SIGRTMIN+4 39) SIGRTMIN+5 40) SIGRTMIN+6 41) SIGRTMIN+7 42) SIGRTMIN+8 43) SIGRTMIN+9 44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+13 48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13 52) SIGRTMAX-12 53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9 56) SIGRTMAX-8 57) SIGRTMAX-7 58) SIGRTMAX-6 59) SIGRTMAX-5 60) SIGRTMAX-4 61) SIGRTMAX-3 62) SIGRTMAX-2 63) SIGRTMAX-1 64) SIGRTMAX $
|
常用的几个信号量:
信号名称 |
信号数 |
描述 |
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 2 3 4 5 6 7
| lockdir="${TARGET_PATH}/${LOCK_DIR}.lock" if mkdir "$lockdir"; then trap 'rm -rf "$lockdir"' INT TERM EXIT else echo "Exit by mutex control" exit 1 fi
|
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 2 3 4 5 6
| exist=`ps aux | grep '/usr/local/bin/[f]fmpeg'` if [ "$exist" == "" ]; then echo "没有ffmpeg命令在运行" else echo "有ffmpeg命令在运行" fi
|
其中在ps
命令中过滤grep
本身的方法有两种
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 2 3 4
| for element in "${array[@]}" do echo "$element" done
|
同时获取索引和值
1 2 3 4
| for index in "${!array[@]}" do echo "$index ${array[index]}" done
|
获取数组中元素的数量:
参考: How to split a string into an array in Bash?
例子:
1 2 3 4 5 6 7 8 9 10 11 12 13
| $ string="字段1,字段2 字段3,字段4" $ IFS=', ' read -r -a array <<< "$string" $ echo "${array[0]}" 字段1 $ echo "${array[1]}" 字段2 $ echo "${array[2]}" 字段3 $ echo "${array[3]}" 字段4 $ echo "${array[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 2 3
| while IFS= read -r line; do echo "line is ${line}" done < $file_path
|
参考: 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' )
|
命令详解: Reading output of a command into an array in Bash