Bash

從命令的輸出中提取兩個值

  • May 24, 2015

我在腳本中使用以下命令來獲取合成 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到兩個工作,然後連接結果?

使用臨時變數並沒有錯:變數是用來儲存要多次使用的數據。

在這種情況下,您可以將兩個 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 中執行。您無法從中獲取變數或控制其輸出如何與其他變數穿插。

引用自:https://unix.stackexchange.com/questions/205186