从 shell 脚本中的 pargs 解析进程命令行参数

从 shell 脚本中的 pargs 解析进程命令行参数

我在 bash 脚本(Java 进程)中获取 PID 列表,并且必须分析它们的命令行参数以确定每个 PID 对应于哪个服务器实例。

目前我使用 sed/cut 这样做:

  PARGS=$(pargs -l $PID)
  PARGS_ARR=($PARGS)
  NODE='UNKNOWN'
  for ARG in ${PARGS_ARR[@]}
  do
    # trim single quotes 
    ARG=$(echo $ARG | sed "s/'//g")

    # split by equals sign
    ARGL=$(echo $ARG | cut -f1 -d=)
    ARGR=$(echo $ARG | cut -f2 -d=)

    if [ "$ARGL" == "-DnodeId" ]; then
      NODE=$ARGR
    fi
  done

但由于大量的命令行参数(每个 PID 大约 20-30 个),它的运行速度非常慢。

有没有办法以某种方式解析命令行参数并使用单个命令获取 key=>value 解析?

答案1

的输出是什么pargs -l $PID样的?从您的代码来看,它似乎是一行包含格式的所有命令行参数,例如:

arg1=val1 arg2=val2

-DnodeId如果是这样,您可以使用命令收集参数的值sed

$ ARGS="-DfirstArg=foo -DanotherArg=bar -DnodeId=1234 -DlastArg=baz"
$ echo "$ARGS" | sed -r 's/.*-DnodeId=([^ ]+).*/\1/g'
1234

所以你的脚本可能会变成:

PARGS=$(pargs -l $PID)
NODE='UNKNOWN'
if [ -n "$(grep "DnodeId" <(echo "$PARGS"))" ]; then
    NODE=$(echo "$PARGS" | sed -r 's/.*-DnodeId=([^ ]+).*/\1/g')
fi

答案2

如果您关心的是右侧的内容(=如果左侧的内容是)-DnodeId,则可以执行以下操作:

NODE=$(pargs -l $PID| awk -F '-DnodeId=' '{sub(" .*","",$2);print $2}')

这将打印图案右侧的所有内容-DnodeId=,但不包括第一个空格。如果命令行上有多个-DnodeId,则它仅适用于第一个。

每行处理多个-DnodeId也是可能的:

NODES=($(pargs -l $PID| awk -F '-DnodeId=' '{
          for(i=2;i<=NF;i++){
              sub(" .*","",$i);
              print $i
          }
        }'
))

答案3

看来你所做的事情肯定会很慢,因为每次你var=$(command substitute)您必须停止并等待其输出,然后才能进行下一步。我敢打赌,如果您只是在流中处理它,您会等待更少的时间sed,stream editor:

NODE="$(pargs -l $PID | sed -rn '/(-DnodeId)=(\S*)/{s//\2/pq}')"

我不太确定单引号 - 我刚刚在手机上输入了这个 - 但是sed's y如果您仍然需要它,函数当然可以处理它。

上面的 Josh 演示了一个失败案例。可能只需添加以下内容就会简单得多:

${NODE:?PID not found...quitting}

运行上面之后sed命令。

在我看来,这些不一定已经被线分隔,我们可以用另外 1 条线轻松处理这个问题|pipe- 仍然全部在一个数据流中,同时还考虑了多个匹配的可能性:

. <<PIDSED /dev/stdin
    $(pargs -l $PID |\
        sed -rn 's/(-DnodeId)=(\S*)/\
            echo "NODE$((i=i+1))=\2" ;/gp' |\
        . /dev/stdin)
PIDSED

答案4

bash使用而不是外部进程来处理参数

for ARG in "${PARGS_ARR[@]}"
do
  # trim single quotes 
  ARG=${ARG//\'}

  # split by equals sign
  IFS="=" read ARGL ARGR <<< "$ARG"

  if [[ "$ARGL" == "-DnodeId" ]]; then
    NODE=$ARGR
  fi
done

相关内容