シェルスクリプトから部分文字列 "mode:" の後に数値を抽出する簡潔で読みやすい方法です。

シェルスクリプトから部分文字列 "mode:" の後に数値を抽出する簡潔で読みやすい方法です。

私はこの文字列を持っています:

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

答え1

正規表現はより簡単な解決策です。いくつかのオプションは次のとおりです。

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

PCRE機能が気に入らない場合:

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

このtrコマンドは削除されません。言葉すべてを削除する「モード」数値「モデル」、「」。


本当に好きなら、「パターン」をクリックするまで単語を繰り返します。

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

文字列はすでにシェル変数に含まれているので、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 シェルパラメータの拡張マニュアルで(そしていくつかの詳細を簡単に説明):

  • ${var#pattern}削除する最短プレフィックスパターンマッチ
  • ${var##pattern}削除する最長プレフィックスパターンマッチ
  • ${var%pattern}削除する最短のサフィックスパターンマッチ
  • ${var%%pattern}削除する最長のサフィックスパターンマッチ

「最も短いもの」と「最も長いもの」の違いが重要です。与えられた文字列サフィックスには複数のコロンが含まれています。${tmp%:*}削除する場合にのみ使用してください。最後コロンとその後の文字です。

答え2

perlPCREスタイルの正規表現またはそのバリアントをサポートしている場合は、grep直接一致と1つ以上の数値を使用して値を選択できます。mode

grep -oP 'mode\s+\K\d+'

私はあなたがREが好きではないことを読みましたが、それは非常に単純なパターンなので、ここで説明します。

  • これまでの内容\Kはすべて一致する必要があるリバースパターンですが、結果には含まれません。
  • \sスペースと一致します(通常スペースまたは商標) サフィックスには、+次の 1 つ以上が必要です。
  • \d数値サフィックス(0.. 9)と一致するには、+次のうち1つ以上が必要です。

必要な値に数値以外のテキストを含めることができることがわかっている場合\d+に置き換えることができます。[^:]+ここでは[^:]、コロン()を:除くすべての項目が一致します。

引用する

答え3

シンプルで直接的なsed解決策は

sed -n 's/.*mode \([0-9]*\):.*/\1/p'

3つ()の代わりに単一のコマンドを使用してくださいawk | tr | head。解決策が読みやすいと思うと助けることはできません。

答え4

私はすでに提供されているShellパラメータ拡張ソリューションが好きですが、bashが利用できない場合は、次のAWKチェーンが同じように機能します。

... |awk -F"mode " '{print$2}' | awk -F: '{print $1}'

最初の awk 呼び出しは、「mode」で文字列を分割し、それに続く内容を返します。

2番目の呼び出しはこれを:に分割し、前の内容を返します。

私にとっては、これはBashパラメータ拡張よりも読みやすくなります。しかし、より冗長で速度も遅くなる可能性があります(AWKはかなり高速であることが知られていますが、2回始まるオーバーヘッドはそれに反対します)。

関連情報