我在 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