解析 rsync 统计信息,仅包含 bash 的行文件数
Parse rsync stats, line Number of files with bash only
我需要像这样解析 rsync 统计信息:
Number of files: 265 (reg: 189, dir: 10, link: 66)
Number of created files: 18
Number of deleted files: 4
Number of regular files transferred: 24
Total file size: 121.67K bytes
Total transferred file size: 0 bytes
Literal data: 0 bytes
Matched data: 0 bytes
File list size: 0
File list generation time: 0.001 seconds
File list transfer time: 0.000 seconds
Total bytes sent: 9.15K
Total bytes received: 33
sent 9.15K bytes received 33 bytes 18.37K bytes/sec
total size is 121.67K speedup is 13.24
使用如下命令解析每一行相当容易:
$(echo "$rawstats" | grep -Po '(?<=Number of files: ).*')
现在我需要解析第一行。我在这里找到了一个 Perl 解决方案:
但我不想依赖 perl,Dan Lowe 的回答在所有情况下都不起作用,因为 () 中的内容可能是 reg:、dir:、link:(甚至其他我忽略的)的任意组合.
即:
265 (reg: 189, dir: 10, link: 66)
265 (dir: 10, link: 66)
265 (link: 66)
所以我正在尝试构建正确的正则表达式以传递给 grep -P
到目前为止我发现:
(\d+) \((?:([a-z]+): (\d+)(?:, )?)*\)?
这是这样匹配的:
[0] is a null string
[1]=265
[2]=link
[3]=66
我预期的结果:
[1]=265
[2]=reg
[3]=189
[4]=dir
[5]=10
[6]=link
[7]=66
我看不出如何改进我的结果。
最好的结果是 bash 关联数组,如 :
[reg]=189
[dir]=10
[link]=66
感谢您的帮助
类似的东西 - 有点冗长,但是..
echo "$rawstats" | awk -f zalem.awk
其中 zalem.awk 是:
BEGIN {
FS="[()]"
}
/^Number of files:/ {
np=split(, npA,/, */)
gsub(/[^0-9]/,"",)
for(i=1;i<=np;i++) {
printf("%s (", )
for(j=i;j<=np;j++)
printf("%s%s%s", (j==i)?"":" ", npA[j], (j==np)?")"ORS:",")
}
}
产量:
265 (reg: 189, dir: 10, link: 66)
265 (dir: 10, link: 66)
265 (link: 66)
看起来你的要求已经改变了...(特定于 gawk)zalem.awk
:
BEGIN {
FS="[(),:]"
}
/^Number of files:/ {
for(i=2;i<NF;i++)
printf("[%d]=%s\n", i-1, gensub(/[[:space:]]/, "","g",$i))
}
纯 Bash 与 Grep
我认为没有理由避免使用 Perl,它在文本解析方面非常方便。但这是一个纯 Bash 实现,它从包含 rsync 统计输出的 rawstats
变量中生成一个关联数组 stats
:
declare -A stats=()
label_regex='Number of files:'
num_of_files_line=$(grep -E "$label_regex" <<< "$rawstats")
regex="$label_regex ([0-9]+)"
[[ $num_of_files_line =~ $regex ]] && stats['total']=${BASH_REMATCH[1]}
while read -r k v; do stats["$k"]="$v"; done < <( \
regex='([a-z]+): ([0-9]+)'
while [[ $num_of_files_line =~ $regex ]]; do
match=${BASH_REMATCH[0]}
printf "%s %s\n" "${BASH_REMATCH[1]} ${BASH_REMATCH[2]}"
num_of_files_line=${num_of_files_line#*"$match"}
done
)
进程替换 (<( ... )
) 允许在循环中使用 stats
变量。管道将创建不共享变量的 sub-shells。
Perl
这里是一个类似的 Perl 实现,我可能会使用它:
declare -A stats=()
while read -r k v; do stats["$k"]="$v"; done < <( \
printf "%s\n" "$rawstats" | \
perl -ne '/Number of files: (\d+)/ or next; print "total \n"; print " \n" while (/([a-z]+): (\d+)/g)' \
)
在每个 UNIX 机器上的任何 shell 中使用任何 awk:
$ cat tst.awk
BEGIN { FS="[(): ,]+" }
sub(/^Number of files: [0-9]+ /,"") {
for (i=2; i<NF; i+=2) {
printf "[%s]=%d\n", $i, $(i+1)
}
exit
}
$ awk -f tst.awk file
[reg]=189
[dir]=10
[link]=66
如果您愿意,您可以调整该输出以填充 bash 关联数组(google)。
我需要像这样解析 rsync 统计信息:
Number of files: 265 (reg: 189, dir: 10, link: 66)
Number of created files: 18
Number of deleted files: 4
Number of regular files transferred: 24
Total file size: 121.67K bytes
Total transferred file size: 0 bytes
Literal data: 0 bytes
Matched data: 0 bytes
File list size: 0
File list generation time: 0.001 seconds
File list transfer time: 0.000 seconds
Total bytes sent: 9.15K
Total bytes received: 33
sent 9.15K bytes received 33 bytes 18.37K bytes/sec
total size is 121.67K speedup is 13.24
使用如下命令解析每一行相当容易:
$(echo "$rawstats" | grep -Po '(?<=Number of files: ).*')
现在我需要解析第一行。我在这里找到了一个 Perl 解决方案:
但我不想依赖 perl,Dan Lowe 的回答在所有情况下都不起作用,因为 () 中的内容可能是 reg:、dir:、link:(甚至其他我忽略的)的任意组合.
即:
265 (reg: 189, dir: 10, link: 66)
265 (dir: 10, link: 66)
265 (link: 66)
所以我正在尝试构建正确的正则表达式以传递给 grep -P 到目前为止我发现:
(\d+) \((?:([a-z]+): (\d+)(?:, )?)*\)?
这是这样匹配的:
[0] is a null string
[1]=265
[2]=link
[3]=66
我预期的结果:
[1]=265
[2]=reg
[3]=189
[4]=dir
[5]=10
[6]=link
[7]=66
我看不出如何改进我的结果。 最好的结果是 bash 关联数组,如 :
[reg]=189
[dir]=10
[link]=66
感谢您的帮助
类似的东西 - 有点冗长,但是..
echo "$rawstats" | awk -f zalem.awk
其中 zalem.awk 是:
BEGIN {
FS="[()]"
}
/^Number of files:/ {
np=split(, npA,/, */)
gsub(/[^0-9]/,"",)
for(i=1;i<=np;i++) {
printf("%s (", )
for(j=i;j<=np;j++)
printf("%s%s%s", (j==i)?"":" ", npA[j], (j==np)?")"ORS:",")
}
}
产量:
265 (reg: 189, dir: 10, link: 66)
265 (dir: 10, link: 66)
265 (link: 66)
看起来你的要求已经改变了...(特定于 gawk)zalem.awk
:
BEGIN {
FS="[(),:]"
}
/^Number of files:/ {
for(i=2;i<NF;i++)
printf("[%d]=%s\n", i-1, gensub(/[[:space:]]/, "","g",$i))
}
纯 Bash 与 Grep
我认为没有理由避免使用 Perl,它在文本解析方面非常方便。但这是一个纯 Bash 实现,它从包含 rsync 统计输出的 rawstats
变量中生成一个关联数组 stats
:
declare -A stats=()
label_regex='Number of files:'
num_of_files_line=$(grep -E "$label_regex" <<< "$rawstats")
regex="$label_regex ([0-9]+)"
[[ $num_of_files_line =~ $regex ]] && stats['total']=${BASH_REMATCH[1]}
while read -r k v; do stats["$k"]="$v"; done < <( \
regex='([a-z]+): ([0-9]+)'
while [[ $num_of_files_line =~ $regex ]]; do
match=${BASH_REMATCH[0]}
printf "%s %s\n" "${BASH_REMATCH[1]} ${BASH_REMATCH[2]}"
num_of_files_line=${num_of_files_line#*"$match"}
done
)
进程替换 (<( ... )
) 允许在循环中使用 stats
变量。管道将创建不共享变量的 sub-shells。
Perl
这里是一个类似的 Perl 实现,我可能会使用它:
declare -A stats=()
while read -r k v; do stats["$k"]="$v"; done < <( \
printf "%s\n" "$rawstats" | \
perl -ne '/Number of files: (\d+)/ or next; print "total \n"; print " \n" while (/([a-z]+): (\d+)/g)' \
)
在每个 UNIX 机器上的任何 shell 中使用任何 awk:
$ cat tst.awk
BEGIN { FS="[(): ,]+" }
sub(/^Number of files: [0-9]+ /,"") {
for (i=2; i<NF; i+=2) {
printf "[%s]=%d\n", $i, $(i+1)
}
exit
}
$ awk -f tst.awk file
[reg]=189
[dir]=10
[link]=66
如果您愿意,您可以调整该输出以填充 bash 关联数组(google)。