Bash

在 shell 腳本中提取子字元串“mode:”之後的數值的簡潔但易讀的方法

  • March 23, 2022

我有這個字元串:

DMT           mode 4: 640x480 @ 60Hz 4:3, clock:25MHz progressive

我想從中提取模式編號(第一個 : 之前的部分),在此範例中為 4。正如您可能期望的那樣,模式編號可能是 1 或 2 位數字,並且不能依賴它之前的文本在完全相同的字元長度上。

我有一個可行的解決方案:

$picked = "DMT           mode 4: 640x480 @ 60Hz 4:3, clock:25MHz progressive"
echo $picked | awk -F"mode " '{print $2}' | tr : '\n' | head -n1

但我覺得必須有一種更優雅的方式來做到這一點。現在優雅且易於學習,以後再閱讀(因此,可能不涉及正則表達式)。我的夢想命令是這樣的:echo $picked | 在“模式”之間:“

這裡還有一些範例來顯示需要可解析的輸入範圍:

CEA           mode 7: 720x480 @ 60Hz 16:9, clock:27MHz x2 interlaced
CEA  (native)  mode 16: 1920x1080 @ 60Hz 16:9, clock:148MHz progressive
DMT           mode 58: 1680x1050 @ 60Hz 16:10, clock:146MHz progressive

正則表達式將是更直接的解決方案:一些選項:

echo "$picked" | grep -oP '(?<=mode )\d+'
echo "$picked" | grep -oP '(?<=mode )[[:digit:]]+'

如果您不喜歡 PCRE 功能:

echo "$picked" | grep -oE 'mode [[:digit:]]+' | tr -d 'mode '

tr命令不會刪除單詞“mode”,而是刪除所有字元“m”、“o”、“d”、“e”、“”。


如果你真的喜歡awk,遍歷單詞直到你點擊“mode”

echo "$picked" | awk '{for (i=1; i<NF; i++) if ($i == "mode") {print $(i+1); exit}}' | tr -d :

由於您已經在 shell 變數中包含了字元串,那麼如何替換 bash 參數:

tmp=${picked#*mode }    # remove up to "mode "
value=${tmp%%:*}        # remove the colon and everything after

然後

$ declare -p picked tmp value
declare -- picked="DMT           mode 4: 640x480 @ 60Hz 4:3, clock:25MHz progressive"
declare -- tmp="4: 640x480 @ 60Hz 4:3, clock:25MHz progressive"
declare -- value="4"

參考手冊中的3.5.3 Shell Parameter Expansion(並忽略一些更精細的點):

  • ${var#pattern}刪除匹配模式的最短前綴
  • ${var##pattern}刪除匹配模式的最長前綴
  • ${var%pattern}刪除匹配模式的最短後綴
  • ${var%%pattern}刪除匹配模式的最長後綴

“最短”和“最長”之間的區別是關鍵。請注意,給定的字元串在後綴中包含多個冒號—— using ${tmp%:*}only 刪除最後一個冒號和後面的字元。

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