0

not really sure how to describe this but I'll do my best to explain what I'm doing. I've been BASHing my head against the wall trying to figure out how to pass a string ex. {command:$1} into a script and have it populate the $1 with it's respective value.

What i'm trying to attempt is converting my lsof output to json, grabbing the columns I want after parsing with awk and formatting, setting key, values with my script.

My Script

#!/bin/bash

FORMAT=$1
(
IFS=' ';
while read line; do
    set -- $line;
    echo $FORMAT
done
)

My command line call

lsof -Pn | grep LISTEN | awk '{print $1,$2,$3,$4,$5,$8,$9}' | ~/.scripts/json "{command:\$1,pid:\$2,user:\$3,fd:\$4,protocol:\$5:\$6,host:\$7}"

My return

{command:$1,pid:$2,user:$3,fd:$4,protocol:$5:$6,host:$7}

if I remove the forward slashes I get

{command:,pid:,user:,fd:,protocol::,host:}

What I'm expecting

{command:webstorm,pid:5270,user:daviddiefenderfer,fd:142u,protocol:IPv4:TCP,host:127.0.0.1:6942}

I'm not sure what exactly is happening but I would love to understand, my guess is that the variables $[1-7] are being evaluated before they get into the while loop, where there is no values.

0

You are confusing awk's $1, $2, ... field accessors with the shell's $1, $2, ... positional parameters. Also, a pipe does not set positional parameters, it just provides the output from the left-hand side as the input to the right-hand side.

Don't forget that JSON requires string values to be quoted, including object property names:

json=$(
    lsof -Pn | grep LISTEN \
    | awk '
        BEGIN {template = "{\"command\":\"%s\",\"pid\":\"%s\",\"user\":\"%s\",\"fd\":\"%s\",\"protocol\":\"%s:%s\",\"host\":\"%s\"}\n"}
        {printf template, $1, $2, $3, $4, $5, $8, $9}
    '
)
~/.scripts/json "$json"
1

You are reinventing the wheel (and incorrectly). Use jq to generate your JSON.

 lsof -Pn | 
   awk '/LISTEN/ {print $1,$2,$3,$4, $5,$8,$9}' |
   jq -R 'split(" ") |
         {
           command: .[0],
           pid: .[1],
           user: .[2],
           fd: .[3],
           protocol: "\(.[4]):\(.[5])", 
           host: .[6]
         }'

If you version of jq supports regular expressions, you can drop the call to awk as well:

lsof -Pn | jq -R '
  select(match("LISTEN")) |
  [splits("  *")] |
  {
    command: .[0],
    pid: .[1],
    user: .[2],
    fd: .[3],
    protocol: "\(.[4]):\(.[7])", 
    host: .[8]
  }'

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.