行から数値を抽出して変数に保存するには?

行から数値を抽出して変数に保存するには?

私はこれが非常に簡単な質問だと思い、Googleが質問の一部に多くの回答を見つけましたが、一緒に接続しようとするとうまくいかず、理由を理解できません。

シナリオは次のとおりです。

  1. テキストの多いファイルがあります。
  2. 行の1つが次のパターンと一致します。foo = 1700;
  3. 抽出したい1700
  4. 後でスクリプトで参照できるようにbashスクリプト変数に保存したいと思います。

3段階を超えられません。私が試したことは次のとおりです。

sed -nE 's/^foo = //p' file | sed -nE 's/;//p'

これは次のように印刷されます。

1700

大丈夫です。しかし、空白などを整える必要がある場合はどうすればいいですか?*/が利用できない場合は+どうすればいいのかわかりません。他の回答を使用*/+置き換えることができないことを理解しているので、これを行う方法がわかりません。 grepのマニュアルページを見ましたが、その用語を検索してもグループオプションは表示されません。私はawkでこの問題を解決する方法を知っていると思いますが、常に正規表現関数が少し不明瞭であり、コマンドラインスクリプトにエスケープが多すぎるため、理想的にはこれがこの問題を解決する唯一の方法ではありません。 。

答え1

  1. まず、数値をキャプチャする方法を紹介します。

    $ echo 'foo = 1700;' | sed -n -e 's/^foo = \([0-9]\+\).*/\1/p'
    1700
    

    これはデフォルトsedの基本 Regular Expressions (BRE) を使用します。 sed-Eオプションで拡張正規表現(ERE)を使用することもできます。

    echo 'foo = 1700;' | sed -n -E -e 's/^foo = ([0-9]+).*/\1/p'
    1700
    

    [0-9]+括弧内のサブ式は(... )1つ以上の数字をキャプチャします。これは「キャプチャグループ」と呼ばれ、次に置き換えるために使用されます\1最初キャプチャグループ - キャプチャグループが複数ある場合は、\1、\2、\3などとして使用できます。

    この場合、sedスクリプトは行全体を\ 1キャプチャグループにのみ置き換えようとし、成功すると修正された行を印刷します。

  2. sed次に、出力を変数に入れたいです。あなたはこれでやるコマンドの置き換え。例えば

    $ myvar=$(echo 'foo = 1700;' | sed -n -E -e 's/^foo = ([0-9]+).*/\1/p')
    $ echo $myvar
    1700
    
  3. スクリプトで使用するには、ファイルをパイプするのではなく、sedの引数として使用しますecho ...

    myvar=$(sed -n -E -e 's/^foo = ([0-9]+).*/\1/p' file)
    
  4. スペースをトリミングしたり、オプションの=先行スペースや周囲のオプションのスペースなどがある可能性がある行を処理します。

    myvar=$(sed -n -E -e 's/^[[:space:]]*foo[[:space:]]*=[[:space:]]*([0-9]+).*/\1/p' file)
    

    sedの一部のバージョン(少なくともGNU sed、たぶん他のバージョン)はこれを理解しているperl's \sので、次のように短縮できます。

     myvar=$(sed -n -E -e 's/^\s*foo\s*=\s*([0-9]+).*/\1/p' file)
    

答え2

完全性のためにおよびをサポートする正規表現の実装を使用して、次のgrepことを実行できます。-operl-P

grep -Po 'foo\s*=\s*\K\d+'

どこ:

  • \s空白文字と一致
  • *0個以上の先行原子。たとえば、\s*ゼロ個以上の空白文字を一致させます。
  • \d10進数と一致します(通常は同じです[0123456789]が、[0-9]通常は文字は使用されません)。
  • +1つ以上の以前の原子と一致します。
  • \K一致する部分(コンテンツがeep、またはK出力の場合)の開始をリセットします。grep -oo

したがって、これは、指定された行に複数の数字が表示されても、1つ以上の数字と両方にfoo=許可されている空白数のすべてのシーケンスを印刷します。=

を使用すると、一致する部分全体ではなく、指定されたキャプチャグループが一致するアイテムを印刷するために、後にpcregrep数字を指定することもできます。-o

pcregrep -o1 'foo\s*=\s*(\d+)'

移植可能であれば、実際に実際を使用できますperl。 ::

perl -lne 'print $1 for m{foo\s*=\s*(\d+)}g'

答え3

数値を選択するとしますfoo

echo 'foo = 1700;' | awk '$1=="foo" {print $NF+0}'
1700

デフォルトではawk空白(単一の空白ではない)に分割されます。NFはフィールド数です。この場合、3は$NF3番目の空白フィールドの文字列値です。+0この文字列を1700;数値に変換します1700

同じ行では機能しますfoo = 1700;が、同じ行では機能しませんfoo=1700;。あなたの質問によると、余分な空白を削除することに興味があるのか​​、データに空白がなく、唯一の境界点が=あるのか​​わかりません。;存在するかどうかにかかわらず、スペースを無視するには、次を使用することをお勧めしますsed

echo 'foo=1700;' | sed -n 's/^foo *= *//p' | sed -e 's/;$//' -e 's/ *$//'
1700

答え4

awk '{for(i=1;i<=NF;i++){if($i ~ /foo/ && $0 ~ /foo.*=.*[0-9]*/){gsub(";","",$(i+2));print $(i+2)}}}' filename

テストを経てうまく機能しました

関連情報