命令获得数据集的最小,最大,中值和平均值
1. 概述
当我们在 Linux 中管理文件时,我们可能希望从数字列表或具有数字内容的文件中提取统计数据。
在本教程中,我们将专注于借助多种 Linux 工具获取此类数据集的最小值和最大值、中值和均值。
2. 创建我们的示例文件
在我们开始之前,让我们创建一个名为data.txt的文件,我们将使用它来测试我们的策略:
$ cat << eof > data.txt
10
32
4.23
4
223
-53
eof
3.使用awk
awk (GNU/AWK) 是一个值得我们关注的强大工具。它允许我们逐条记录地处理文本并创建报告。 awk的一个优点是它预装在许多 Linux 发行版中。
3.1. 仅使用awk
使用我们对想要实现的目标的了解,让我们创建一个awk脚本并将其保存在名为calculate.awk的文件中:
#!/usr/bin/env awk -f
{
sum += $1
nums[NR] = $1 # We store the input records
}
END {
if (NR == 0) exit #To avoid division by zero
asort(nums) # Here, we sort the array that
#+ contains the stored input
median = (NR % 2 == 0) ? # Let's be carefull with the
#+ short-if syntax
( nums[NR / 2] + nums[(NR / 2) + 1] ) / 2 \
:
nums[int(NR / 2) + 1]
# We used "(NR / 2) + 1", instead "NR/2 + 1", just for
#+ the sake of clarity; to be more verbose
mean = sum/NR
#Let's beautify the output
printf \
"min = %s, max = %s, median = %s, mean = %s\n",\
nums[1],\
nums[NR],\
median,\
mean
}
让我们仔细看看代码。
NR变量包含到目前为止看到的输入记录总数的值。我们在END模式之后执行的代码中使用了NR,因为它在所有输入都用完时执行。因此,我们可以确认NR与我们数据集的基数具有相同的值。
在这段代码中,我们使用了这样一个事实,即如果数组nums是一个有限、封闭且有序的集合,那么它的下界和上界分别是最小和最大元素。
我们调用第一个和第n个元素是因为asort函数 对数组数据进行排序,并且该数据将从 1 索引到某个数字n(在我们的例子中n = NR)。
现在,有了awk脚本,让我们运行:
$ awk -f calculate.awk data.txt
min = -53, max = 223, median = 7.115, mean = 36.705
3.2. 结合awk和sort
在上一节创建的脚本中,我们使用了awk的asort 函数,但我们可以不用它。
让我们创建一个名为 calculate2.awk的脚本,它与calculate.awk相同 ,但没有asort函数。现在,我们只需要在使用awk之前 借助sort命令 对元素进行排序:
$ sort -n data.txt | awk -f calculate2.awk
min = -53, max = 223, median = 7.115, mean = 36.705
在sort命令中,选项*-n*代表数字排序。
3.3. 拥有我们需要的所有数据
如果我们拥有所需的所有数据怎么办?换句话说,如果我们知道数据集的大小,并且它也已排序(从低到高)怎么办?
让我们创建一个名为calculate3.awk的 awk脚本,以便进行简单的操作和逻辑决策——不需要排序,也不需要数组来存储值:
#!/usr/bin/env awk -f
BEGIN {
if (size % 2 == 0) {
median_position[0] = size/2
median_position[1] = (size/2) + 1
}
else
median_position[0] = int(size/2) + 1
}
NR == 1 { min = $1 }
NR == median_position[0] { a_median[0] = $1 }
NR == median_position[1] { a_median[1] = $1 }
{ sum += $1 }
END {
if (NR == 0) exit
median = (median_position[1]) ? \
(a_median[0] + a_median[1]) / 2 \
: \
a_median[0]
max = $1
mean = sum/size
printf \
"min = %s, max = %s, median = %s, mean = %s\n",\
min,\
max,\
median,\
mean
}
让我们分解一下。由于数据已经从低到高排序,第一条记录将是最小值,最后一条记录将是最大值。 这就是为什么当 NR变量等于 1时我们使用min=$1 ,而 当 NR变量在END模式内时我们使用max=$1。
最后,我们可以在管道中运行脚本:
$ size=$(wc -l < data.txt); sort -n data.txt | awk -v size=$size -f calculate3.awk
min = -53, max = 223, median = 7.115, mean = 36.705
让我们仔细看看管道:
- 在awk -v size=$size中,我们通过知道大小(存储在 size变量中)是奇数还是偶数来传递计算中位数所需的信息
- 在这里,在wc -l < data.txt中,我们得到文件data.txt的行数
在我们所有的示例中,我们可以看到awk的优势之一是我们可以在流程的每个阶段对文本流进行大量控制。
4. 使用datamash
*datamash *是一个非常强大和简单的工具,可以帮助我们进行命令行计算。
这个工具没有预装在 Linux 发行版中,所以我们需要在开始编写单行代码之前安装它。
如果我们使用基于 Debian 的发行版,我们可以使用:
$ sudo apt-get install -y datamash
或者,如果我们使用yum:
$ sudo yum install datamash
对于其他发行版和安装选项,我们可以查阅下载页面 以获取更多说明。
幸运的是,datamash确实具有我们想要应用于数据集的所有操作:
$ datamash min 1 max 1 median 1 mean 1 < data.txt
-53 223 7.115 36.705
在这里,我们指出了每个操作后跟我们要应用它的列。