如果你只是想简单的后台挂起一个命令你可以在末尾加一个&,就可以了,如下
your_command &
echo $!
这种写法中,是依靠了&在shell中可以并行所有命令,或者说是立刻释放左侧命令对shell的控制权,从而让shell立刻去执行右侧命令的能力。而$!可以获取最后一个被放入后台执行的命令所对应的进程ID,注意是最后一个后台执行的进程ID,也就是说,如果你写sleep 5 & sleep 1,那么$!获取到的是sleep 5的进程而不是sleep 1的,如果你直接写sleep 5 ,$!获取不到任何东西。并且当你断开SSH连接,或者触发资源回收时,这个后台进程如果还存在会被回收
因此,当在写一个设计持有化服务的脚本,要注意服务的生命周期,以及明确的获取到服务的进程号,这种情况建议你使用nohup、ps、pgrep、&相互配合,nohup的作用是包裹所负责的命令,使得进程忽略内核传递的SIGHUP信号。ps或者pgrep负责查询服务进程ID,例如如下脚本
#!/bin/bash
#例如有一个脚本后台启动了一个叫做test的进程
nohup /opt/test.sh &
#如果你希望在前台输出准确进程id就用ps直接解析
ps -aux | grep test| grep -v grep | awk '{print $2}'
#但是!!!awk的结果不能在管道中直接写入文件,执行会有问题,所以你可以用pgrep
pgrep -f test > /opt/out
下面用一个例子,来解释 nohup 到底是干了什么
----------这里启动一个1000秒的后台进程 nohup 会在内核中立刻启动一个进程,随后在内核中通过signal(SIGHUP, SIG_IGN)让这个进程自身忽略停止信号,随后execvp(command, args)复用进程执行用户本来的命令,这里任然需要 & 使得进程放入后台
[root@node1 wy]# nohup sleep 1000 &
[1] 40832
[root@node1 wy]# nohup: ignoring input and appending output to ‘nohup.out’
--------------直接在bash中使用这里要回车一下
--------------此时获取$! 拿到的就是包含这个命令的进程
[root@node1 wy]# echo "PID: $!"
PID: 40832
------------查询进程,看到PID是获取到的40832,而PPID是当前SSH连接的会话
[root@node1 wy]# ps -ef | grep sleep
root 40832 14349 0 13:39 pts/1 00:00:00 sleep 1000
root 40844 14349 0 13:39 pts/1 00:00:00 grep --color=auto sleep
[root@node1 wy]# ps -ef | grep 14349
root 14349 9810 0 11:19 pts/1 00:00:00 -bash
root 40832 14349 0 13:39 pts/1 00:00:00 sleep 1000
root 40855 14349 0 13:40 pts/1 00:00:00 ps -ef
root 40856 14349 0 13:40 pts/1 00:00:00 grep --color=auto 14349
---------------断开这次会话连接触发内核的资源回收后,再新建一个会话连接,查询,会发现这个进程本身忽略了资源回收的停止信号,从而交给了顶级进程
[root@node1 ~]# ps -ef | grep sleep
root 40832 1 0 13:39 ? 00:00:00 sleep 1000
root 40913 40886 0 13:40 pts/1 00:00:00 grep --color=auto sleep
使用ps -aux或者ps -ef在获取进程id上都可以,参数的区别是其他细节输出不同而已,但是要注意的是pgrep -f命令输出的进程条数很可能会有多条,这是因为-f做模糊匹配的时候,会把所有有关键字的进程全部搜索出来,所以它的结果里面会有grep本身的进程号等,如果你需要精确的进程号就要用ps进一步解析了,比如如下脚本
#!/bin/bash
tmp=""
#使用 $() 和 拼接结果字符串 的方式找到所有需要的进程id
tmp=$(ps -aux | grep metastore | grep -v grep | awk '{print $2}')
#分割两个命令的结果
tmp+=" "
tmp+=$(ps -aux | grep hiveserver2 | grep -v grep | awk '{print $2}')
#将进程id拆成数组
readarray -t ADDR <<< "$(echo "$tmp" | tr ' ' '\n')"
tmp=""
#遍历数组kill进程
for ids in "${ADDR[@]}"; do
kill -9 "$ids"
echo "kill run-id by $ids"
done
最后,要说一个误区,nohup只负责委派,不负责自动放在后台,比如如下
nohup $REDIS_HOME/bin/redis-server $REDIS_HOME/redis.conf
echo 测试输出 $!
上面这个写法,会出现很多不对劲的问题,比如进程不退出等等,总之这就是一个错误的写法不要这样用
此外,原则上,nohup 它保障了负责进程的生命周期不被自动回收,但在实际使用中最好控制到二进制命令,或者说是保障调用命令的原子性,实在有需要每一层父子命令都应该使用 nohup

586

被折叠的 条评论
为什么被折叠?



