如果你只是想简单的后台挂起一个命令你可以在末尾加一个就可以了如下your_commandecho$!这种写法中是依靠了在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|greptest|grep-vgrep|awk{print $2}#但是awk的结果不能在管道中直接写入文件执行会有问题所以你可以用pgreppgrep-ftest/opt/out下面用一个例子来解释 nohup 到底是干了什么----------这里启动一个1000秒的后台进程nohup会在内核中立刻启动一个进程随后在内核中通过signal(SIGHUP, SIG_IGN)让这个进程自身忽略停止信号随后execvp(command, args)复用进程执行用户本来的命令这里任然需要使得进程放入后台[rootnode1 wy]# nohup sleep 1000 [1]40832[rootnode1 wy]# nohup: ignoring input and appending output to ‘nohup.out’--------------直接在bash中使用这里要回车一下 --------------此时获取$!拿到的就是包含这个命令的进程[rootnode1 wy]# echo PID: $!PID:40832------------查询进程看到PID是获取到的40832而PPID是当前SSH连接的会话[rootnode1 wy]# ps -ef | grep sleeproot4083214349013:39 pts/1 00:00:00sleep1000root4084414349013:39 pts/1 00:00:00grep--colorautosleep[rootnode1 wy]# ps -ef | grep 14349root143499810011:19 pts/1 00:00:00-bashroot4083214349013:39 pts/1 00:00:00sleep1000root4085514349013:40 pts/1 00:00:00ps-efroot4085614349013:40 pts/1 00:00:00grep--colorauto14349---------------断开这次会话连接触发内核的资源回收后再新建一个会话连接查询会发现这个进程本身忽略了资源回收的停止信号从而交给了顶级进程[rootnode1 ~]# ps -ef | grep sleeproot408321013:39 ? 00:00:00sleep1000root4091340886013:40 pts/1 00:00:00grep--colorautosleep从上面的用例中可以发现 nohup 使得进程忽略中断信号并不是立刻就发生的它其实是在父进程消失后让当前进程变成了一个没有血缘的僵尸进程这些进程会被 init 也就是内核初始化进程管理并负责回收使用ps -aux或者ps -ef在获取进程id上都可以参数的区别是其他细节输出不同而已但是要注意的是pgrep -f命令输出的进程条数很可能会有多条这是因为-f做模糊匹配的时候会把所有有关键字的进程全部搜索出来所以它的结果里面会有grep本身的进程号等如果你需要精确的进程号就要用ps进一步解析了比如如下脚本#!/bin/bashtmp#使用 $() 和 拼接结果字符串 的方式找到所有需要的进程idtmp$(ps-aux|grepmetastore|grep-vgrep|awk{print $2})#分割两个命令的结果tmp tmp$(ps-aux|grephiveserver2|grep-vgrep|awk{print $2})#将进程id拆成数组readarray-tADDR$(echo$tmp|tr \n)tmp#遍历数组kill进程foridsin${ADDR[]};dokill-9$idsechokill run-id by$idsdone最后要说一个误区nohup只负责委派不负责自动放在后台比如如下nohup$REDIS_HOME/bin/redis-server$REDIS_HOME/redis.confecho测试输出$!上面这个写法会出现很多不对劲的问题比如进程不退出等等总之这就是一个错误的写法不要这样用此外原则上nohup 它保障了负责进程的生命周期不被自动回收但在实际使用中最好控制到二进制命令或者说是保障调用命令的原子性实在有需要每一层父子命令都应该使用 nohup