Analisando argumentos da linha de comandos do processo a partir de pargs em um shell script

3

Eu obtenho uma lista de PIDs em meus scripts bash (processos Java) e tenho que analisar seus argumentos de linha de comando para determinar a instância do servidor a que cada PID corresponde.

No momento, faço isso usando 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

Mas funciona EXTREMAMENTE LENTA devido ao grande número de parâmetros de linha de comando (cerca de 20 a 30 por cada PID).

Existe uma maneira de, de alguma forma, analisar os parâmetros da linha de comando e obter a chave = > value parse com um único comando?

    
por user1065145 21.03.2014 / 11:05

4 respostas

1

Como é a saída de pargs -l $PID ? Do seu código, parece que é uma única linha contendo todos os argumentos da linha de comando em um formato, por exemplo:

arg1=val1 arg2=val2

Nesse caso, você pode coletar o valor para o argumento -DnodeId com o comando sed :

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

Assim, seu script pode se tornar:

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

Se tudo o que importa é o que vem à direita de = , se o que está à esquerda for -DnodeId , você pode fazer isso:

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

Isso imprimirá o que vier à direita do padrão -DnodeId= até, mas excluindo o primeiro espaço. Se houver mais de um -DnodeId na linha de comando, ele funcionará apenas com o primeiro.

Para lidar com mais de um -DnodeId por linha também é possível:

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

Parece que o que você está fazendo definitivamente seria muito lento, pois toda vez que você var=$(command substitute) você parar e aguardar sua saída antes de passar para a próxima etapa. Eu estou disposto a apostar que você esperaria muito menos se você processasse no fluxo com sed, o stream editor:

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

Eu não tenho certeza sobre as aspas simples - eu apenas digitei isso no meu telefone - mas a função sed's y pode lidar com isso se você ainda precisar.

Acima de Josh, há um caso de falha. Provavelmente seria muito mais simples adicionar:

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

Depois de executar o comando sed acima.

Ocorre-me que estes não estão necessariamente separados por linha, podemos lidar com isso facilmente com mais 1 |pipe - ainda tudo em um fluxo de dados, além de considerar a possibilidade de várias correspondências:

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

Processe os argumentos usando bash , não processos externos

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
    
por 21.03.2014 / 19:09