我有一个两列文件,您可以按如下方式创建
cat > twocol << EOF
007 03
001 03
003 01
137 12
001 11
002 01
002 02
002 03
001 02
002 04
137 94
010 21
001 01
EOF
生成的文件twocol
只包含数字行。
期望的结果
我想执行某种命令twocol
并得到以下结果。(我认为看到它比尝试重述我有点令人困惑的问题标题要好得多 - “按第一列排序,然后第二列排序;输出唯一的第一列一次,但输出所有第二列”。)
001 01
02
03
11
002 01
02
03
04
003 01
007 03
010 21
137 12
94
这与 simplesort
给我的不同,即不同于
001 01
001 02
001 03
001 11
002 01
002 02
002 03
002 04
003 01
007 03
010 21
137 12
137 94
我的工作
我唯一想到的第一个解决方案是我想出的第一个解决方案(在我得到一个像样的awk
脚本之前) - 它与上面粗体的所需结果匹配,使用 的几个实例,awk
一堆bash
,以及来自1的一些帮助。
col_1_max_len=$(awk '
BEGIN{maxl=0;}
{curr=length($1);max1=max1>curr?max1:curr;}
END{print max1}' \
twocol);
len1=$col_1_max_len;
len2=$(awk '
BEGIN{max2=0;}
{curr=length($2);max2=max2>curr?max2:curr;}
END{print max2}' \
twocol);
current_col_1_val="nothing";
while read -r line; do {
current_row="${line}";
col_1_val=$(awk '{print $1}' <<< "${current_row}");
col_2_val=$(awk '{print $2}' <<< "${current_row}");
if [ ! "${col_1_val}" == "${current_col_1_val}" ]; then
printf "%0"$len1"d %0"$len2"d\n" "${col_1_val}" "${col_2_val}";
else
printf "%"$len1"s %0"$len2"d\n" " " "${col_2_val}";
fi;
}; done < <(sort twocol)
我觉得我应该能够使用一次传递awk
,类似于以下答案:2 , 3 , 4 , 5 , ...
如果没有额外的、笨重的、消耗内存的数组,我似乎无法将它拼凑在一起。这种格式也给我带来了一个问题——第一列和第二列中的数字可以有更多位数,而且最好看起来不错。
谁能告诉我如何使用一些不错的 awk
代码获得这个结果 - 最好可以在终端中非常轻松地使用? Perl
也欢迎回答。
哦,我的系统
$ uname -a && bash --version | head -1 && awk --version | head -1
CYGWIN_NT-10.0 MY-MACHINE 3.2.0(0.340/5/3) 2021-03-29 08:42 x86_64 Cygwin
GNU bash, version 4.4.12(3)-release (x86_64-unknown-cygwin)
GNU Awk 5.1.0, API: 3.0 (GNU MPFR 4.2.0-p9, GNU MP 6.2.1)
(我在 Fedora 和 Ubuntu 机器上得到了完全相同的行为。)
编辑
我想出了一个awk
解决方案。看起来一切都很好,很短,但我仍然觉得有问题。
awk '{if (!vals[$1]++) print($0); else print(" ",$2);}' <(sort twocol)
我认为我在数组中使用了一堆内存vals
- 截至目前,我的文件只有约 10k 行,但我希望将其扩大。我以格式进行硬编码,但我不喜欢它,因为我可以有不同长度的字符串。
如果我使用变量进行三遍awk
并传递变量,我可以修复这个问题(格式)。
length1=$(awk '
BEGIN{maxl=0;}
{curr=length($1);max1=max1>curr?max1:curr;}
END{print max1}' \
twocol);
length2=$(awk '
BEGIN{max2=0;}
{curr=length($2);max2=max2>curr?max2:curr;}
END{print max2}' \
twocol);
awk -vlen1=$length1 -vlen2=$length2 '
{
if (!vals[$1]++)
printf("%0*d %0*d\n",len1,$1,len2,$2);
else
printf("%*s %0*d\n",len1," ",len2,$2);
}' <(sort twocol)
结果与所需结果完全匹配(请参阅上面粗体部分),但我希望有一种方法可以通过一次awk
.
谁能分享一些符合我提到的特征的东西?关于不同方法的时间性能和/或内存性能的任何评论也将受到赞赏。
我认为也可以进行排序awk
;我想知道,尤其是它是否可以更有效率。编辑:可以完成,如下所示@steeldriver和@markp-fuso。