从命令的输出中提取两个值

从命令的输出中提取两个值

我在脚本中使用以下命令来获取合成 wifi 信息:

echo "$(
    iw dev wlp1s0 link |
    grep '^\s*SSID:\s' |
    sed -r 's/^\s*SSID:\s//'
) $(
    iw dev wlp1s0 link |
    grep '^\s*signal:\s' |
    sed -r 's/^\s*signal:\s//'
)"

它有效,输出如下:

MySSID -46 dBm

iw dev wlp1s0 link然而,当我知道结果将是相同的时,两次进行相同的调用感觉很愚蠢。另外,我想避免将输出存储iw在临时变量中。

我可以做些什么,也许使用tee,将输出“复制”到iw两个作业,然后连接结果?

答案1

使用临时变量并没有什么问题:变量是用来存储要多次使用的数据的。

在这种情况下,您可以将两个 grep/sed 调用合并为对 GNU grep、sed 或 awk 的单个调用。使用 sed 很容易:传递-n选项以仅输出显式打印的行,并打印进行替换的行。

echo "$(
    iw dev wlp1s0 link |
    sed -nr -e 's/^\s*SSID:\s//p' -e 's/^\s*signal:\s//'
)"

与原始脚本有一个区别:SSID 和信号值按照它们在 的输出中出现的顺序打印iw。如果您想独立于该顺序,那么使用 sed 会很麻烦,因此 awk 将是首选工具。通过这种方法,可以很容易地在一行上获得输出。以下脚本打印每个设置的最后一个值(iw仅输出一个,因此在这种特定情况下它并不重要);更改例如ssid = $0ssid = ssid " " $0打印全部。

iw dev wlp1s0 link | awk '
    $1=="SSID:" {sub(/[^:]*:[[:space:]]*/,""); ssid = $0}
    $1=="signal:" {sub(/[^:]*:[[:space:]]*/,""); signal = $0}
    END {print ssid, signal}
'

一般来说,如果您想将命令的输出发送到两个不同的过滤器,您可以使用tee并将其传递给流程替代。这是一个 bash 功能(来自 ksh93,也存在于 zsh 中,但不存在于普通 sh 中),它概括了管道。该tee命令看到一个文件名,该文件名指定连接到指定命令的管道。

iw dev wlp1s0 link | tee >(
    grep '^\s*SSID:\s' |
    sed -r 's/^\s*SSID:\s//'
  ) |
    grep '^\s*signal:\s' |
    sed -r 's/^\s*signal:\s//'

此方法的一个限制是进程替换中的命令在其自己的子 shell 中运行。您无法从中获取变量或控制其输出如何与其他输出散布。

答案2

这是该命令的一行iw,其输出与您相同。

iw dev wlp1s0 link | grep 'SSID:\|signal' | awk '{printf "%s ", $2$3}'

我的输出:

ZyXEL-AP-2,4GHz -46dBm

答案3

类似的东西?

iw dev wlp1s0 link |
grep -E '^\s*(SSID|signal):\s' |
sed -r 's/^\s*(SSID|signal):\s//' |
awk '{printf $0}'

grep将接受(SSID|signal):,因此它将匹配SSID:signal:

-E是可选的,但如果您不使用它,请考虑转义特殊含义字符。在这里,将是\(SSID\|signal\):

相同的正则表达式可用于该sed部分。

最后,使用awk删除所有尾随换行符(否则,输出将显示为 2 行)。

相关内容