書式設定されたテキストから値を抽出する

書式設定されたテキストから値を抽出する

テキストファイルから変数を抽出する簡単な方法はありますか?

たとえば、次のような出力がありますab

This is ApacheBench, Version 2.3 <$Revision: 1638069 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking bar (be patient)
Finished 1206 requests


Server Software:        Jetty(9.0.z-SNAPSHOT)
Server Hostname:        bar
Server Port:            5500

Document Path:          /foo/1
Document Length:        148 bytes

Concurrency Level:      15
Time taken for tests:   30.041 seconds
Complete requests:      1206
Failed requests:        0
Total transferred:      359686 bytes
HTML transferred:       178636 bytes
Requests per second:    40.15 [#/sec] (mean)
Time per request:       373.643 [ms] (mean)
Time per request:       24.910 [ms] (mean, across all concurrent requests)
Transfer rate:          11.69 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:       47  108  36.0     98     328
Processing:    73  264 782.5    150    7951
Waiting:       73  255 721.5    148    7886
Total:        129  371 783.5    259    8039

Percentage of the requests served within a certain time (ms)
  50%    259
  66%    293
  75%    324
  80%    340
  90%    413
  95%    525
  98%    683
  99%   6421
 100%   8039 (longest request)

name: value値(一致、以下の例を参照)を抽出し、1つのステップで変数に割り当てたいと思います。 (ab一部のデータはcsvにエクスポートできますが、残りはフォーマットされたテキストでのみ使用できることを知っています。)

これまでに私が見つけた最高は次のとおりです。

path=$(cat text|grep 'Document Path:'|awk -F: '{ split($2, z, " "); print z[1]}')
total=$(cat text|grep 'Total transferred:'|awk -F: '{ split($2, z, " "); print z[1]}')
#[...]

しかし、これは少し繰り返されると思います。アッWard - 作業のためのより簡単な方法またはより良いツールはありますか?

答え1

私は通常、次のパターンを使用します。

. <(
    awk 'BEGIN{print "shellvarname=\"value\""}'
)

awkこれは、シェル変数割り当て構文に使用できるステートメントを生成するために使用されます。この結果は(.)からのものです。

特定の要件に応じて、次のオプションがあります。

. <(
    awk -F': *' '
      /Document Path/{printf "%s=\"%s\"\n", "path", $2}
      /Total transferred/{printf "%s=\"%s\"\n", "total", $2}
    ' file
)

またはより短い

. <(
    awk '
      /Document Path/{printf "%s=\"%s\"\n", "path", $3}
      /Total transferred/{printf "%s=\"%s\"\n", "total", $3}
    ' file
)

答え2

1-4単語を含むすべての行を見つけて、を使用して:単語間のスペースを下線で置き換え、ペアvariable=valueで印刷します。その後、コンテンツ全体を転送してeval設定できます。たとえば、

$ awk -F': *' '/^(\S+\s*){1,4}:/{gsub(/ /,"_",$1);print $1"=\""$2"\""}' file
Server_Software="Jetty(9.0.z-SNAPSHOT)"
Server_Hostname="bar"
Server_Port="5500"
Document_Path="/foo/1"
Document_Length="148 bytes"
Concurrency_Level="15"
Time_taken_for_tests="30.041 seconds"
Complete_requests="1206"
Failed_requests="0"
Total_transferred="359686 bytes"
HTML_transferred="178636 bytes"
Requests_per_second="40.15 [#/sec] (mean)"
Time_per_request="373.643 [ms] (mean)"
Time_per_request="24.910 [ms] (mean, across all concurrent requests)"
Transfer_rate="11.69 [Kbytes/sec] received"
Connect="47  108  36.0     98     328"
Processing="73  264 782.5    150    7951"
Waiting="73  255 721.5    148    7886"
Total="129  371 783.5    259    8039"

-F': *フィールド区切り文字:の後にゼロ個以上のスペースが続くように設定します。次に、スクリプトは、行が空白以外の文字(「単語」)が1〜4個発生し、その後に0個以上の空白が続く文字列と一致することを確認します:。この行のため4を使用しています。

Time taken for tests:   30.041 seconds

次に、一致する行の最初のフィールドのすべてのスペースをアンダースコア(gsub(/ /,"_",$1))で置き換え、最初のフィールドanと引用符で囲まれ=た2番目のフィールドを印刷します。文字列を印刷するには引用符で囲む必要があるため、引用符で囲まれたawk文字列を印刷するには引用符$2をエスケープする必要があります" \""

目的の出力が生成されたら、次のようにeval変数を読み取ることができます。

$ eval $(awk -F': *' '/^(\S+\s*){1,4}:/{gsub(/ /,"_",$1);print $1"=\""$2"\""}' file)
$ echo $Transfer_rate 
11.69 [Kbytes/sec] received

または直接インポートしてください。

. <(awk -F': *' '/^(\S+\s*){1,4}:/{gsub(/ /,"_",$1);print $1"=\""$2"\""}' file)

重要:危険です。evalまたは、ファイルをインポートすると、ユーザーが提供したすべてのコードが実行されます。危険であることを確認しません。何らかの理由でスクリプトがawk危険なものを返すと、幸せに実行されます。そのため、上記のコマンドを実行する前に出力結果を確認してください。受け入れられる答えも同じです。他のプログラムから返されたコードを盲目的に実行することは常に危険です。rm ~/*eval


上記はGNUでは機能しますawkが、より単純な実装では機能しませんawk。システムで機能しない場合は、以下を試してください。

. <(awk -F': *' '/.*\s*:   *:/{gsub(/ /,"_",$1);print $1"=\""$2"\""}' file)

関連情報