有没有一种简单的方法从文本文件中提取变量?
例如,给出以下输出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
,请参见下面的示例)并一步将它们分配给变量。 (我知道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]}')
#[...]
但这似乎有点重复awk病房 - 有没有更简单的方法或更适合这项工作的工具?
答案1
我一般使用以下模式:
. <(
awk 'BEGIN{print "shellvarname=\"value\""}'
)
这用于awk
生成一些可在 shell 变量赋值语法中使用的语句。该结果来源于( .
)。
根据您的具体要求,这将是一个选项:
. <(
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': *
字段分隔符设置为:
后跟 0 个或多个空格。然后,该脚本检查该行是否匹配出现 1 到 4 次的非空格字符(“单词”)字符串,后跟 0 个或多个空格,然后是:
。我使用 4 因为这一行:
Time taken for tests: 30.041 seconds
然后,对于匹配的行,将第一个字段中的所有空格替换为下划线 ( gsub(/ /,"_",$1)
),然后打印第一个字段、an=
和引用的第二个字段。因为裸字符串需要加引号才能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)