【问题标题】:How to capture the result of a system call in a shell variable?如何在 shell 变量中捕获系统调用的结果?
【发布时间】:2010-10-17 10:02:10
【问题描述】:

我们想要构建一个每天晚上运行的脚本(杀死并重新启动一个 java 进程)。为此,我们需要捕获进程号(因为可能有多个 java 进程在运行)。下面的命令基本上是我们将用来获取进程号的命令,可能在 grep 末尾带有一个正则表达式。除非有更好的建议。

root#ps -e |grep  'java'
18179 pts/0    00:00:43 java

我们想知道如何解析上面的输出并将其放入 shell 变量中,以便我们可以使用下面的 kill 命令。

kill -9 ${processid}
wait 10

注意1:我们不能依赖正常的服务停止命令的原因是因为进程有时不想死。而且我们必须手动使用kill命令。

【问题讨论】:

    标签: java linux shell scripting


    【解决方案1】:

    我知道这是旧的,但是呢:

    pidof java | xargs kill
    

    【讨论】:

      【解决方案2】:

      如果你按照你的建议去做,你最终可能会捕获 grep 本身并杀死它(因为你的 grep 命令包含你正在搜索的 java 字符串)。您可以通过排除 grep(使用另一个 grep!)来解决此问题:

      pid=`ps -e | fgrep java | fgrep -v grep | awk '{print $1}'`
      # check pid has a value
      # kill $pid
      

      您可能还喜欢ps -e -opid,args

      更好的选择是使用pgrep(1)pkill(1)(如果您的系统有它们)。不再有管道、seds、awks、cuts、xargs:

      pkill -9 java
      

      【讨论】:

      • 我几乎发布了同样的东西,但是 ps -e 没有列出 cmd 参数(至少在我的盒子上),所以在 grep 输出中不存在意外捕获“grep java”命令本身的危险.
      • 正确,Jay,至少对于 Linux。我仍然更喜欢 pkill,但看起来我是少数派。
      • 您也可以在 grep 中的第一个字符周围加上括号,如 grep [j]ava grep 将其视为正则表达式并查找 j,但命令行不会匹配该模式。 :) 这样做让我觉得很脏,但效果很好......
      【解决方案3】:

      有几个选项可以解决这个问题。如果你使用 bash,那么 shell 变量 '$!'将包含最后一个分叉的子进程的 PID。因此,在您启动 Java 程序后,请执行以下操作:

      echo $! > /var/run/my-process.pid
      

      然后,在您的 init 脚本停止 Java 进程之后:

      # Get the pidfile.
      pid=$(cat /var/run/my-process.pid)
      
      # Wait ten seconds to stop our process.
      for count in $(1 2 3 4 5 6 7 8 9 10); do
          sleep 1
          cat "/proc/$pid/cmdline" 2>/dev/null | grep -q java
          test $? -ne 0 && pid="" && break
      done
      
      # If we haven't stopped, kill the process.
      if [ ! -z "$pid" ]; then
          echo "Not stopping; terminating with extreme prejudice."
          kill -9 $pid
      fi
      

      完成后确保删除 pidfile。

      【讨论】:

      • “偏见”?这是玩笑还是错字?
      • 当我在早上喝咖啡之前发布答案时会发生这种情况。
      • 另外,如果你有 'seq' 命令,你可以做 'seq 1 10' 而不是手动计数。不过,并非总是适用于所有 Linux 风格。
      【解决方案4】:

      杀死它:

      ps -e | grep java | cut -f1 -d' ' | xargs kill -9
      

      在变量上存储 PID:

      export JAVAPID=`ps -e | grep 'java' | cut -f1 -d' '`
      

      检查它是否有效:

      echo $JAVAPID
      

      【讨论】:

        【解决方案5】:

        我使用这样的东西:

        kill $(ps -A | grep java | cut -b 1-5)
        

        【讨论】:

          【解决方案6】:

          您可以使用反引号和 cut(或 awk,如果愿意)轻松地将 PID 或 PID 列表放入变量中,以仅检索 PID 字段:

          [user@host ~]$ ps -e | grep java | cut -d' ' -f1
          12812
          12870
          13008
          13042
          13060
          

          请注意,在上面的示例中,我有多个 Java 进程正在运行,因此有多个值。如果你把它保存到一个像这样的变量中:

          JAVA_PROCS=`ps -e | grep java | cut -d' ' -f1`
          

          如果需要,您可以遍历进程以终止它们:

          for proc in $JAVA_PROCS; do
              kill -9 $proc; 
          done
          

          当然,如果您只检索一个进程,则无需迭代,您可以将其运行为:

          kill -9 $JAVA_PROCS
          

          【讨论】:

            【解决方案7】:
            ps aux | grep java | awk '{print $1}' | xargs kill -9
            

            这里有一个解释:

            ps aux 为您提供所有进程的列表

            grep java 为您提供名称和命令行参数包含字符串“java”的所有进程

            awk '{print $1}' 通过空格将 grep 命令的输出解析为列,并仅重新打印第一列

            xargs kill -9 将 awk 命令的每个结果作为参数传递给 kill -9 命令

            【讨论】:

            • 跳过 grep:ps aux | awk '/java/ { print $1 }' :)
            • 感谢您的提示;我对 awk 的了解还不够,不知道该怎么做。我会保留我的答案,因为它对我个人来说更容易理解,但我很高兴你提出了这个建议。
            • 你不应该有一个 grep -v grep 来阻止它收集 grep 的 pid(因为它的命令行包含单词 java)?
            • 技术上是的;我忽略了它有两个原因。首先,当 kill 命令运行时,该进程 ID 将失效,因此将其留在其中并没有什么坏处(尽管您会收到一条警告消息)。其次,它使新手理解的调用链不那么复杂。不过,你有一个很好的观点。
            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2022-11-23
            • 1970-01-01
            • 1970-01-01
            • 2011-10-24
            • 2013-12-24
            • 2011-04-20
            相关资源
            最近更新 更多