셀러리에는 프로세스가 많기 때문에 서버에서 셀러리를 다시 시작하고 싶습니다. 모든 프로세스 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는 연속 공백으로 분할됩니다.개행 포함예를 들어 배열에 매핑하십시오.
$ 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/})
~해야 한다single_pid
PID를 얻기 위해 추가 처리가 필요하지 않도록 별도의 PID 배열이 생성되고 선행 및 후행 공백이 제거됩니다 .
오류 출력에 따르면 분명히 그렇지 않다는 사실은 다음 두 가지 이유 중 하나를 암시합니다.
쉘의 IFS 값을 수정했습니다.
사용 중인 쉘은 인용되지 않은 변수 확장을 토큰화하지 않습니다.
zsh
, 출력 형식은xtrace
기본 동작으로 파일을 사용하고 있음을 나타냅니다. 즉, 명령 대체 시 IFS 분할을 수행함에도 불구하고 위의 코드는 해당 셸에서 계속 작동합니다. 에서 개행으로 분할하려면zsh
다음을 사용하는 것이 좋습니다.array=(${(f)"$(pgrep -- $CELERY_PROGRAM_NAME)"})
그러나 이는 현재 값에 대한 의존성을
bash
제거합니다 .readarray
$IFS
1 실제로 개행 문자를 제거하려면 다음을 사용할 수 있습니다.${PID//$'\n'/}
답변2
피해야 할 또 다른 옵션은 pgrep/pkill
사용자 정의 출력입니다 ps
.
ps
목록 프로세스 및 인쇄 형식/필드에서 사용자 정의를 수행할 수 있습니다.
많은 필드가 있는 모든 프로세스가 나열 되므로 ps -ef
pid를 얻는 것이 번거로울 수 있습니다.
while은 ps -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
형식을 사용하는 경우 기본적으로 do -splitting 으로 바꾸거나 값에 관계없이 개행으로 분할 하도록 바꾸십시오 .)xtrace
${PID}
${=PID}
$IFS
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