一旦变量发生变化,如何评估字符串中的 bash 参数

一旦变量发生变化,如何评估字符串中的 bash 参数

不太确定如何描述这一点,但我会尽力解释我在做什么。我一直BASH把头靠在墙上试图弄清楚如何传递一个字符串 ex。{command:$1}到脚本中并让它$1用它各自的值填充。

我想要尝试的是将我的输出转换为 json,使用我的脚本进行解析和格式化、设置键和值lsof之后获取我想要的列。awk

我的脚本

#!/bin/bash

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

我的命令行调用

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}"

我的归来

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

如果我删除正斜杠我得到

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

我在期待什么

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

我不确定到底发生了什么,但我很想理解,我的猜测是变量$[1-7]在进入 while 循环之前正在被评估,其中没有值。

答案1

你正在重新发明轮子(而且是错误的)。用于jq生成 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]
         }'

如果您的版本jq支持正则表达式,您也可以删除对以下内容的调用awk

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

答案2

您将 awk 的$1, $2, ...字段访问器与 shell 的$1, $2, ...位置参数混淆了。此外,管道不设置位置参数,它只是提供左侧的输出作为右侧的输入。

不要忘记 JSON 需要引用字符串值,包括对象属性名称:

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"

相关内容