文章目录
写在前面
这些是笔者在投递、查看、修改和删除任务时一般常用的操作。
比如test1.sh
是shell文件内容为:
echo "this is test shell"
比如test2.py
是python文件内容为:
print("this is python output")
投递任务
在linux操作中,执行任务有几种方式:
【1】直接在窗口执行
一般是在短时间可执行完成的命令可使用该方法
sh test1.sh
python test2.py
【2】用nohup ... &
在后台直接运行
假如示例的test1.sh和test2.py的执行需要1个小时
nohup sh test1.sh > test1.sh.o 2> test1.sh.e &
nohup python test2.py > test2.py.o 2> test2.py.e &
这里>
是将正确日志输出到.o,2>
是错误日志输出到.e。
以上两种实际的运行方式是相同的,都是在没有对资源进行申请的情况下直接运行。
两者的区别是:
- 前者是在当前窗口直接运行,关掉终端界面相当于中止程序;
- 后者(nohup)是在后台执行,比如用的xshell终端,那么关掉xshell界面依旧在服务器上运行。
【3】从方式【1】直接转到方式【2】
如果一开始以为某脚本运行时间不长,用了sh test1.sh
直接执行,但是发现执行了1分钟没出来结果,想换成后台执行,可以这样操作:
- 先使用快捷键
ctrl + z
,将当前任务暂停; - 执行
jobs
,查看任务序号,例如是下面显示的话,则序号是1。
如果有nohup过任务且未执行完,序号会+1,比如下面这个序号是2。$ jobs [1]+ Stopped sh test1.sh
$ jobs [2]+ Stopped sh test1.sh
- 执行
bg %n
,n是任务序号,将暂停任务(第n
个任务)后台运行(相当于在原始执行命令行后加 &)。
注意,此时的输出日志,因为没有定向到文件,则会直接打印到当前界面中。$ bg %n nohup sh test.sh &
当然,ctrl+z
只是暂停任务,如果还想将任务在当前窗口继续,执行fg %1
就是与bg相对,相当于将任务放到前台当前界面执行。
【4】使用qsub
投递计算节点
如果是共用的服务器,任务资源使用应利用qsub
进行投递。因为在投递时会对资源和线程进行申请,所以当分配合理的资源和线程时,执行过程不会很拥挤。而如果使用前两种方式,当执行大量任务时超过了服务器的负荷,容易出现服务器的堵塞甚至瘫痪。
qsub -cwd -l vf=20 -l p=16 -l h=${HOST} -V -S /bin/sh test1.sh
qsub -wd ${odir} -l vf=20 -l p=16 -l h=${HOST} -V -S /bin/sh test1.sh
比如,这里申请20个内存,16个线程,将脚本test1.sh投递到指定的节点${HOST}。
-cwd
是输出的.o/.e的日志文件到当前目录,也可以用-wd ${odir}
输出到odir下。
查看任务
【1】直接查看
第1种运行方式,由于是当前窗口下执行,所以查看是否运行完成就在当前窗口。
【2】jobs
查看在后台执行的任务
加-l
会增加显示任务的pid。
$ jobs -l
[1]+ Running nohup sh test1.sh > test1.sh.o 2> test1.sh.e &
# 如果切换了目录:后面还会显示你后台运行的这个脚本所在目录
$ jobs -l
[1]+ Running nohup sh test1.sh > test1.sh.o 2> test1.sh.e & (wd: /dirxxx)
【3】用qstat
查看qsub投递的任务
qstat
执行qstat
后,默认是只看到自己投递的任务信息,各列是:
名称 | 说明 |
---|---|
job-ID | 任务job id |
prior | 优先级 |
name | 任务名 |
user | 用户名 |
state | 运行状态, r:运行中;qw:等待中; |
submit/start at | 投递时间/开始运行时间 |
queue | 投递的计算节点 |
slots ja-task-ID |
如果看所有用户投递的任务列表:加-u \*
qstat -u \*
【4】使用top
查看运行中的命令
jobs
和qstat
一般查看的只是执行命令的状态,想要看具体命令在执行消耗资源,可在任务投递所在节点,使用如下命令:
top -ca -u username
加-ca
是显示执行的命令并按内存排序,-u
是查看指定用户执行的命令。显示的信息包含:
表头 | 说明 |
---|---|
PID | 进程id |
USER | 用户名 |
PR | 优先级 |
NI | nice值。负值:高优先级,正值:低优先级 |
VIRT | 进程使用的虚拟内存总量(kb)。VIRT=SWAP+RES |
RES | 进程使用的、未被换出的物理内存大小(kb)。RES=CODE+DATA |
SHR | 共享内存大小(kb) |
S | 进程状态。D=不可中断的睡眠状态 R=运行 S=睡眠 T=跟踪/停止 Z=僵尸进程 |
%CPU | 上次更新到现在的CPU时间占用百分比 |
%MEM | 进程使用的物理内存百分比 |
TIME+ | 进程使用的CPU时间总计,单位1/100秒 |
COMMAND | 进程的命令名/命令行 |
【4】使用ps aux
查看详细的执行命令
虽然使用top可查看命令,事实上,top查看命令是实时的动态变化的。在使用top -ca
时,显示的命令可能受电脑屏大小的影响,过长的命令显示不全。
想要查看完整的命令,最好的方式还是使用ps aux
。这个是直接显示了当前节点所有运行中的命令,如果查看自己运行的命令,借助grep
查找。比如:
ps aux | grep "test1.sh"
显示的各列信息与top的比较相似,但是打印出来的是完整的命令。
表头 | 说明 |
---|---|
USER | 用户编号(不是名称) |
PID | 进程id |
%CPU | CPU时间占用百分比 |
%MEM | 进程使用的物理内存百分比 |
VSZ | 占用虚拟内存大小 |
RSS | 占用内存大小 |
TTY | 终端的次要装置号码 |
STAT | 进程状态 |
START | 进程开始时间 |
TIME | 执行时间 |
COMMAND | 进程的命令名/命令行 |
修改任务
执行过程中,如果想修改脚本,又不想中止任务,怎么做?
当然,默认我们要修改的地方一定是还没有执行到的步骤。
比如,投递的脚本test3.sh
代码是:
echo "this is test2 shell"
python test4.py
echo "this is test2 END"
sh test5.sh
其中,test4.py代码是:
print("this is test4 output")
test5.sh代码是:
echo "this is test5 shell"
这里test3.sh是执行了四个步骤,第一步是echo打印,第二步是执行了python脚本test4.py
,第三步也是echo打印,第四步是执行shell脚本test5.sh
。
分两种情况,要修改的脚本是当前投递的脚本还是当前投递脚本的内嵌的某步骤的脚本。
【1】修改投递脚本的内嵌脚本
比如,执行test3.sh过程中,想要修改test4.py脚本代码,如果没有执行到test4.py步骤,是可以直接编辑test4.py文件。同样的,想要修改test5.sh脚本也可以直接修改。
也就是,内嵌脚本修改后,脚本名称不变情况下,执行时用的就是更改后的脚本。
【2】修改投递脚本
就是说,要修改test3.sh
自身。比如,想把第三步中的echo内容进行修改:
echo "this is test2 end [`date`]"
先别急着修改原文件!
当任务投递后台执行任务时,默认会将执行的脚本直接放到内存中,也就是想要修改正在执行的任务,需要到内存中修改脚本。内存中的脚本路径:
/proc/${pid}/fd/255
其中,pid就是上面可以用top
或者ps aux
可查找到的进程id。就是直接修改内存里的这个文件/proc/${pid}/fd/255
才能生效。
需要注意的是,修改原来的文件test3.sh会发生什么?
- 如果你在
vi
编辑变更文件时,会自动生成有后缀是~
的备份文件,比如编辑了xxx.sh
后自动生成了xxx.sh~
文件(这个~
文件就是你修改前的文件)。那么,你修改了xxx.sh文件,执行中的任务并不受影响,且还会按照原来的脚本执行(执行加了~
的文件)。 - 如果你在
vi
编辑时,并不会自动生成后缀是~
的备份文件,那么,在修改执行中的脚本时,内存路径的文件/proc/${pid}/fd/255
会认为任务被删除,这应该不是我们希望的。
所以,修改当前投递的脚本内容,修改/proc/${pid}/fd/255
。
删除任务
【1】ctrl+c
如果是直接sh test1.sh的方式运行,关闭窗口或者ctrl + c
便是中止任务。
【2】kill删除
使用nohup后台执行,如何删除任务?
- 当nohup时的界面未关闭时,可通过
kill -9 %n
(n是任务投递的序号1、2、3)删除任务; - 如果界面关闭或
kill
后仍在运行或者投递脚本中的内嵌脚本仍在运行,可先用top -ca -u username
看自己username运行的任务PID(或用ps aux
找任务PID),然后使用kill -9 PID
(任务的PID)删除对应的运行中的任务。
【3】qdel
删除任务
如果删除单个进程,找到PID然后用kill删除。如果使用了qsub
投递任务,删除任务则使用qdel
命令进行删除。
- 使用job-ID删除:
qdel -j
删除指定jobID任务qdel -j jobid qdel -j jobid1,jobid2 # 删除多个任务
- 使用
qdel -u username
删除该用户的所有任务qdel -u username
附:
各种Linux命令索引:《鸟哥的私房菜》-命令和用语速查表:http://cn.linux.vbird.org/linux_basic/1010index.php