我想从服务器重新启动 celery,因为 celery 有很多进程,我编写这个脚本来查询所有进程 id 并杀死它:
#
# stop celery process
#
PID=`ps -ef|grep -w ${CELERY_PROGRAM_NAME}|grep -v grep|cut -c 9-15`
if [ -z "${PID}" ]; then
echo "Process aready down..."
else
array=(${PID//\n/})
for var in "${array[@]}"
do
single_pid=`echo ${var} | awk 'gsub(/^ *| *$/,"")' `
if [[ ${single_pid} -gt 1 ]]; then
kill -15 "${single_pid}"
else
echo "Process ${PROGRAM_NAME} not found"
fi
done
fi
从日志中,我发现pid没有转换为数组,下一步没有正确分割。我从 GitHub Actions 远程运行此脚本。这是 GitHub Actions 的日志输出:
======CMD======
cd /opt/apps/pydolphin
. /opt/apps/pydolphin/restart.sh
======END======
err: +/opt/apps/pydolphin/restart.sh:16> PROGRAM_NAME=schedulespider.py
err: +/opt/apps/pydolphin/restart.sh:17> CELERY_PROGRAM_NAME=celery
err: +/opt/apps/pydolphin/restart.sh:18> PYTHON_BIN_PATH=/usr/bin/python3
err: +/opt/apps/pydolphin/restart.sh:23> PID=+/opt/apps/pydolphin/restart.sh:23> ps -ef
err: +/opt/apps/pydolphin/restart.sh:23> PID=+/opt/apps/pydolphin/restart.sh:23> grep -w celery
err: +/opt/apps/pydolphin/restart.sh:23> PID=+/opt/apps/pydolphin/restart.sh:23> grep -v grep
err: +/opt/apps/pydolphin/restart.sh:23> PID=+/opt/apps/pydolphin/restart.sh:23> cut -c 9-15
err: +/opt/apps/pydolphin/restart.sh:23> PID=' 9777
err: 9778
err: 9779
err: 9865
err: 9867
err: 9868 '
err: +/opt/apps/pydolphin/restart.sh:24> [ -z ' 9777
err: 9778
err: 9779
err: 9865
err: 9867
err: 9868 ' ']'
err: +/opt/apps/pydolphin/restart.sh:27> array=( ' 9777
err: 9778
err: 9779
err: 9865
err: 9867
err: 9868 ' )
err: +/opt/apps/pydolphin/restart.sh:28> var= 9777
err: 9778
err: 9779
err: 9865
err: 9867
err: 9868
err: +/opt/apps/pydolphin/restart.sh:30> single_pid=+/opt/apps/pydolphin/restart.sh:30> echo ' 9777
err: 9778
err: 9779
err: 9865
err: 9867
2021/07/19 06:00:52 Process exited with status 1
err: 9868 '
err: +/opt/apps/pydolphin/restart.sh:30> single_pid=+/opt/apps/pydolphin/restart.sh:30> awk 'gsub(/^ *| *$/,"")'
err: +/opt/apps/pydolphin/restart.sh:30> single_pid='9777
err: 9778
err: 9779
err: 9865
err: 9867
err: 9868'
err: +/opt/apps/pydolphin/restart.sh:31> [[ '9777
err: 9778
err: 9779
err: 9865
err: 9867
err: 9868' -gt 1/opt/apps/pydolphin/restart.sh:31: bad math expression: operator expected at `9778\n9779\n...'
err: ]]
我读了我的脚本,但没有发现哪里出了问题,我该怎么做才能使它工作?
答案1
如果您决定编写自己的“终止循环”而不是简单地使用pkill
,那么至少使用pgrep
来获取 PID 列表,不受可能的前导/尾随空格的阻碍 - 而不是尝试对 的输出进行切片和切块ps
:
array=($(pgrep -- "${CELERY_PROGRAM_NAME}"))
pgrep
或者直接循环输出
for single_pid in $(pgrep -- "${CELERY_PROGRAM_NAME}"); do ...
pgrep
生成一个 PID 列表,每行一个,默认的 bash IFS 将在连续的空格上分割包括换行符将它们映射到数组 ex。
$ pgrep ssh
1194
3688
22642
22754
$ array=($(pgrep ssh))
$ declare -p array
declare -a array=([0]="1194" [1]="3688" [2]="22642" [3]="22754")
或者可以使用readarray -t array < <(pgrep ssh)
.
无需测试字符串是否为空,因为如果没有元素,循环将不会运行。
至于为什么您的实现不起作用,将从1${PID//\n/}
中删除文字n
字符。假设只包含数值,那应该什么也不做,并且PID
PID
array=(${PID//\n/})
应该创建了一个单独的 PID 数组,还删除了前导和尾随空格,这样就single_pid
不需要进一步处理来获取 PID。
事实上,它显然没有(基于您的错误输出)表明以下两个原因之一:
您已修改 shell 的 IFS 值
您使用的 shell 不会对不带引号的变量扩展进行分词。
zsh
,您的输出格式xtrace
表明您正在使用的文件具有默认行为,例如,尽管在命令替换时进行 IFS 分割,所以上面的代码仍然可以在该 shell 中工作。要在 中按换行符分割zsh
,您宁愿使用:array=(${(f)"$(pgrep -- $CELERY_PROGRAM_NAME)"})
不过,这
bash
会readarray
消除对当前值的依赖$IFS
。
1要实际删除换行符,您可以使用${PID//$'\n'/}
答案2
另一种要避免的选择pgrep/pkill
是自定义ps
的输出。
ps
可以在列表过程和打印格式/字段中进行自定义。
请注意,它将ps -ef
列出具有许多字段的所有进程,并且获取 pid 可能会很麻烦。
whileps -e -o pid,comm
将给出两列输出
PID COMMAND
1 systemd
2 kthreadd
3 rcu_gp
4 rcu_par_gp
9 mm_percpu_wq
10 ksoftirqd/0
(...)
1002 gdm3
1013 sshd
1031 php-fpm7.4
1032 php-fpm7.4
1044 nginx
1065 nmbd
(many more lines)
(或-o pid= -o comm=
删除标题)。
如果我正在寻找的进程位于${CELERY_PROGRAM_NAME}
(并且不包含反斜杠或空白字符),我可以使用
ps -e -o pid= -o comm= | awk -v proc="${CELERY_PROGRAM_NAME}" '$2==proc { print $1}'
获取 pid。
使用
PID=$(ps -e -o pid= -o comm= | awk -v proc="${CELERY_PROGRAM_NAME}" '$2==proc { print $1})
检查非空后,并考虑到这${PID}
是一个以换行符分隔的 pid 列表,我可以使用(假设$IFS
包含换行符,默认情况下):
for pid2 in ${PID}
do
...
done
(如果使用zsh
作为输出的格式xtrace
建议您这样做,请替换${PID}
为${=PID}
to do $IFS
-splitting 就像bash
默认情况下那样,或者替换为${(f)PID}
在换行符上拆分,无论 的值如何$IFS
)。
选择
一些选择ps
(查看man ps
全部)
ps -p 1234 -o tty,args
(列出 pid 1234 的 tty 和 args )ps -t pts/1,pts/3 -f
(列出 tty pts/1 和 pts/3 中的所有内容)ps -u archemar
(列出属于 archemar 的所有进程)
HP/UX 和 procps 实现ps
还支持-C
根据进程名称查询进程的选项。