根据一列对文件进行分区

根据一列对文件进行分区

我有以下数据集:

M1  1   1233
M2  1   3212
M3  1   55323
M4  1   4444233
M5  1   23444
M6  1   555333
M7  1   55567
M8  2   22224
M9  2   55566
M10 2   4567
M11 3   44242
M12 3   234234
M13 4   2233
M14 4   2442
M15 4   322352
M16 4   235242
M17 4   2324524
M18 5   232342
M19 6   2322523
M20 6   2332523

我想根据第二列的值创建一个数组。我想在1第二列中的所有行中应用其他命令,在2第二列中的行中应用其他命令,依此类推,并将它们保存在不同的文件中,但我不知道如何执行此操作。我尝试使用 while命令,但所有尝试都失败了。

该代码的输出应该是数组每个索引中原始文件的子集;例如:

索引 i1

M1  1   1233
M2  1   3212
M3  1   55323
M4  1   4444233
M5  1   23444
M6  1   555333
M7  1   55567

索引 i2

M8  2   22224
M9  2   55566
M10 2   4567

依此类推,直到

索引 i6

M19 6   2322523
M20 6   2332523

在这些索引中,我想应用其他命令。

我如何在 shell 脚本和/或 awk 中执行此操作?

答案1

您可以从 awk 获得最佳结果:

awk '{ print > "index i"$2 }' < input

您也可以纯粹在 shell 中执行此操作:

while read a b c
do
        printf '%s\n' "$a $b $c" >> "index i$b"
done < input

awk 解决方案具有以下优点:

  • 它将覆盖现有文件。 shell 脚本将附加到现有文件中。 (我想这可能就是您想要的。在这种情况下,您可以通过使用>>而不是>在 awk 脚本中来实现。)
  • awk 脚本保留输入文件的间距。 shell 脚本将多个空格缩减为单个空格。
  • 对于大数据文件,awk 脚本可能会稍微快一些。

答案2

添加到 G-Man 的答案:是的,您可以仅使用 sh 获得完全相同的结果(因为这是您重复问题中的规范那里,这是我在 G-Man 回答之前 9 小时回答的)。

有一个内置函数set允许您为$1 $2等等赋值$3。以下是 bash 手册页的引用(这也适用于 sh):

设置[{-选项| +选项 | -- }] arg ...

set 命令的第三个用途是将 shell 的位置参数的值设置为指定的 args。要更改位置参数而不更改任何选项,请使用“--”作为要设置的第一个参数。如果不存在args,set命令将清除所有位置参数(相当于执行“shift $#”。)

所以我们可以这样做:

set -f
while read ln; do
    set -- $ln
    printf '%s\n' "$ln" >> "index i"$2
done < input
set +f

在 中set -- $ln$ln被分成多个字段,第 n 个字段被分配给第 n 个位置参数。

下一行的引用$ln确保内容的完整性(保留间距等)。

set -fset +f为了防止像 * 和 ? 这样的通配字符?在文件中免于混乱set。感谢斯科特提出这个问题。

相反printf,我最初使用的是echo.但多亏了斯科特的第二条评论(如果对手将一行更改为、echo等选项,那么就会感到困惑),而是用来防止这种情况。-n-eechoprintf

这表明 sh 可能不是此类工作的理想选择。至少使用支持正则表达式的 bash。但是,如果你尝试的话,这是可行的。

至于 awk,嗯,它不是“稍微快一点”,而是在不考虑磁盘 IO 的情况下快一个数量级。所以优先使用awk。

顺便说一句,我相信你没有听说过这样一句话:“如果两个答案是一个太多,那么两个问题就是两个太多”。

因为我刚刚说过了;)

但下次做出选择并坚持下去,这样我们就能集中精力。

答案3

命令

  for i in `awk '{if(!seen[$2]++)print $2}' y.txt`;do awk -v i="$i" 'BEGIN {print "index i"i}$2==i {print $0}END {print "========================================"}' y.txt; done

输出

index i1
M1  1   1233
M2  1   3212
M3  1   55323
M4  1   4444233
M5  1   23444
M6  1   555333
M7  1   55567
========================================
index i2
M8  2   22224
M9  2   55566
M10 2   4567
========================================
index i3
M11 3   44242
M12 3   234234
========================================
index i4
M13 4   2233
M14 4   2442
M15 4   322352
M16 4   235242
M17 4   2324524
========================================
index i5
M18 5   232342
========================================
index i6
M19 6   2322523
M20 6   2332523
========================================

相关内容