プロセスを強制終了するときに不正なPIDを通知するのはなぜですか

プロセスを強制終了するときに不正なPIDを通知するのはなぜですか

今、私はこのスクリプトを使用してプロセスを再起動しています:

PID=`ps -ef|grep -w ${APP_NAME}|grep -v grep|cut -c 9-15`
if [[ ${PID} -gt 1 ]]; then
  kill -9 ${PID}
else
  echo "Process not found"
fi

しかし、GitHub Actions からリモート サーバーでこのスクリプトを実行すると、次のエラーが表示されます。

======CMD======
cd /opt/apps/dolphin-acientbay/libs
. /opt/apps/dolphin-acientbay/libs/upgrade.sh

======END======
err: +/opt/apps/dolphin-acientbay/libs/upgrade.sh:13> JAVA_HOME=/***/.sdkman/candidates/java/11.0.11.hs-adpt 
err: +/opt/apps/dolphin-acientbay/libs/upgrade.sh:14> APP_HOME=/opt/apps/dolphin-acientbay/libs 
err: +/opt/apps/dolphin-acientbay/libs/upgrade.sh:15> APP_NAME=dolphin-acientbay-service-1.0.0-SNAPSHOT.jar 
err: +/opt/apps/dolphin-acientbay/libs/upgrade.sh:17> PID=+/opt/apps/dolphin-acientbay/libs/upgrade.sh:17> ps -ef
err: +/opt/apps/dolphin-acientbay/libs/upgrade.sh:17> PID=+/opt/apps/dolphin-acientbay/libs/upgrade.sh:17> grep -w dolphin-acientbay-service-1.0.0-SNAPSHOT.jar
err: +/opt/apps/dolphin-acientbay/libs/upgrade.sh:17> PID=+/opt/apps/dolphin-acientbay/libs/upgrade.sh:17> grep -v grep
err: +/opt/apps/dolphin-acientbay/libs/upgrade.sh:17> PID=+/opt/apps/dolphin-acientbay/libs/upgrade.sh:17> cut -c 9-15
err: +/opt/apps/dolphin-acientbay/libs/upgrade.sh:17> PID=' 19882 ' 
2021/05/30 11:46:21 Process exited with status 1
err: +/opt/apps/dolphin-acientbay/libs/upgrade.sh:18> [[ ' 19882 ' -gt 1 ]]
err: +/opt/apps/dolphin-acientbay/libs/upgrade.sh:19> kill -9 ' 19882 '
err: /opt/apps/dolphin-acientbay/libs/upgrade.sh:kill:19: illegal pid:  19882 

以下は完全なスクリプトですupgrade.sh:

#!/usr/bin/env bash

set -u

set -e

set -x

JAVA_HOME="/root/.sdkman/candidates/java/11.0.11.hs-adpt"
APP_HOME="/opt/apps/dolphin-acientbay/libs"
APP_NAME="dolphin-acientbay-service-1.0.0-SNAPSHOT.jar"

PID=`ps -ef|grep -w ${APP_NAME}|grep -v grep|cut -c 9-15`
if [[ ${PID} -gt 1 ]]; then
  kill -9 ${PID}
else
  echo "Process not found"
fi

sleep 5

count=`ps -ef | grep ${APP_NAME} | grep -v "grep" | wc -l`
if [[ ${count} -lt 1 ]]; then
  nohup ${JAVA_HOME}/bin/java -Xmx128M -Xms128M -jar \
  -Xdebug -Xrunjdwp:transport=dt_socket,suspend=n,server=y,address=0.0.0.0:5021 \
  -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/opt/apps/dolphin-acientbay/ \
  ${APP_HOME}/${APP_NAME} >> ./acientbay.log &
  sleep 5
else
  echo "process aready exists!"
  exit 1
fi

pid のスペースを削除するために、kill process コマンドを次のように調整してみました (xargs は pid の空白をトリミングします)。

 echo "${PID}" | xargs | kill -9

それは私に教えてくれます:

err: /opt/apps/dolphin-acientbay/libs/upgrade.sh:kill:19: not enough arguments

答え1

問題の原因は次のとおりです:

PID=`ps -ef|grep -w ${APP_NAME}|grep -v grep|cut -c 9-15`
  1. 変数を使用するときは、二重引用符で囲みます。例: "$APP_NAME" または "${APP_NAME}"。

    ちなみに、中括弧は、文字列内の他のテキストから変数を区別する必要がある場合にのみ必要です。たとえば、変数が実際には だが$APP、 を含む文字列でそれを使用する必要がある場合_NAME、 - を使用します。"${APP}_NAME"これにより、シェルによって変数名の一部として解釈されることが防止されます_NAME

  2. の代わりにバックティックを使用しています$()。バックティックは何年も前から非推奨になっていますが、それには十分な理由があります。バックティックはここでの問題の原因ではなく、単にやめるべき悪い習慣です。

  3. cutは、1 文字以上で区切られるフィールドを抽出するのに適したツールではありません。フィールド間に 1 つの (正確に 1 つの) 区切り文字がある場合にのみ有効です。多くのテキスト ファイルでは、フィールド区切り文字として 1 つ以上のスペース (および/またはタブやその他の空白文字) が使用されており、 では簡単に処理できませんcut。代わりにawkまたは を使用してくださいperl

    を使用すると、cut -c 9-15$PID に少なくとも 1 つの余分なスペース文字がキャプチャされます。 から PID を抽出するにはps -efawk '{print $2}'の代わりにを使用しますcut -c 9-15

  4. pgrep "$APP_NAME"名前でプロセスの PID を取得するために使用します。またはpgrep -f "$APP_NAME"、検索する文字列が引数である場合 (たとえば、スクリプトの名前が引数としてインタープリターに渡される場合)。

    カーゴカルティングはps | grep ... | grep -v grep、何十年も前から時代遅れになっています。いずれにしても、それを実行する良い方法ではありませんでした。 ps -ef | awk '/[p]rocess_name/ {print $2}'は常により良い方法でした ([]パターンの最初の文字を で囲むと、awk や grep などが ps 出力で自分自身と一致するのを防ぐことができます)。しかし、 によってそれさえも時代遅れになっていますpgrep

    ps自体には、-Cプロセス名を一致させるオプション、hヘッダーを抑制するオプション、および-o出力内容を指定するオプションがありますps。例:ps h -o pid -C "$APP_NAME"

これらすべてを要約するには、次のようにします。

    PID=$(pgrep "$APP_NAME")
or
    PID=$(pgrep -f "$APP_NAME")
or
    PID=$(ps h -o pid -C "$APP_NAME")

ところで、もしどれでもpgrepまたはによって複数の PID が返される可能性があるためps、出力をスカラー変数ではなく配列にキャプチャする必要があります。たとえば、次のコードは、すべての表示可能な bash プロセスの PID を配列にキャプチャします$BASHPIDS

$ BASHPIDS=( $(ps h -o pid -C bash) )

$ typeset -p BASHPIDS
declare -a BASHPIDS=([0]="68910" [1]="71059" [2]="71634" [3]="71641" [4]="71643"
[5]="71680" [6]="71683" [7]="71684" [8]="71687" [9]="71693" [10]="71712" [11]="72394"
[12]="72568" [13]="72589" [14]="970222" [15]="974740" [16]="1078757" [17]="1278073"
[18]="1365082" [19]="1405642" [20]="1458889" [21]="2278763" [22]="2466442" [23]="2876831"
[24]="2955565" [25]="3260896" [26]="3261235" [27]="3269020" [28]="3281961" [29]="3702104" 
[30]="4038149")

何らかの理由でそれらすべてを殺したい場合は、次のようにします。

kill "${BASHPIDS[@]}"

答え2

このコマンドは問題を解決します:

 echo "${PID}" | xargs kill -9

関連情報