awk 如何在行内从左到右排序?

awk 如何在行内从左到右排序?

我有一个带有 xml 类型标签的大型数据文件。每行引用一个唯一的项目并包含不同数量的属性字段。我需要根据该行中的编号标签从最低到最高对行进行排序,并删除重复项。是否可以使用 awk 在每一行中执行此操作?

<ITEM ID='81'>,< 1>KWIKSET</1>,< 2>PASS</2>,< 7>KNOB</7>,< 5a>RIGHT</5a>,< 8c>BRASS</8c>,< 2>TYLO</2>,< 2>PASS</2>,< 5a>RIGHT</5a>,< 8c>BRASS</8c>
<ITEM ID='82'>,< 1>KWIKSET</1>,< 4a>PRIVACY</4a>,< 7>KNOB</7>,< 8b>SATIN</8b>,< 8c>CHROME</8c>,< 2>TYLO</2>,< 4a>PRIVACY</4a>,< 8b>SATIN</8b>,< 8c>CHROME</8c>
<ITEM ID='83'>,< 1>KWIKSET</1>,< 8b>POLISHED</8b>,< 8c>BRASS</8c>

答案1

我会为此使用 perl :

perl -MList::Util=uniq -F, -lane '
    $item = shift @F;
    @fields = uniq sort @F;
    print join ",", $item, @fields;
' file

输出:

<ITEM ID='81'>,< 1>KWIKSET</1>,< 2>PASS</2>,< 2>TYLO</2>,< 5a>RIGHT</5a>,< 7>KNOB</7>,< 8c>BRASS</8c>
<ITEM ID='82'>,< 1>KWIKSET</1>,< 2>TYLO</2>,< 4a>PRIVACY</4a>,< 7>KNOB</7>,< 8b>SATIN</8b>,< 8c>CHROME</8c>
<ITEM ID='83'>,< 1>KWIKSET</1>,< 8b>POLISHED</8b>,< 8c>BRASS</8c>

还可以写成更难以理解的台词:

perl -MList::Util=uniq -F, -lape '$"=","; $_="@{[$F[0], uniq sort @F[1..$#F]]}"' file

我希望标签内容不包含逗号。

答案2

您只使用 awk 有什么原因吗?要解决您的问题,您需要首先将数据拆分为每个单元,排序,删除重复项,然后重新加入。虽然您可以使用大多数有能力的编程或脚本语言(甚至 C)来完成此操作,但当已经有工具能够满足您的需要时,是否真的值得重新发明轮子?

如果您发布的数据是您正在使用的数据的真实表示,您可以使用以下命令快速处理它:

$ cat RAW_DATA
<ITEM ID='81'>,< 1>KWIKSET</1>,< 2>PASS</2>,< 7>KNOB</7>,< 5a>RIGHT</5a>,< 8c>BRASS</8c>,< 2>TYLO</2>,< 2>PASS</2>,< 5a>RIGHT</5a>,< 8c>BRASS</8c>
<ITEM ID='82'>,< 1>KWIKSET</1>,< 4a>PRIVACY</4a>,< 7>KNOB</7>,< 8b>SATIN</8b>,< 8c>CHROME</8c>,< 2>TYLO</2>,< 4a>PRIVACY</4a>,< 8b>SATIN</8b>,< 8c>CHROME</8c>
<ITEM ID='83'>,< 1>KWIKSET</1>,< 8b>POLISHED</8b>,< 8c>BRASS</8c>
$ while read line; do echo "$(cut -d, -f1 <<< "$line"),$(cut -d, -f2- <<< "$line" | tr ',' '\n' | sort -n | uniq | paste -sd,)"; done < RAW_DATA
<ITEM ID='81'>,< 1>KWIKSET</1>,< 2>PASS</2>,< 2>TYLO</2>,< 5a>RIGHT</5a>,< 7>KNOB</7>,< 8c>BRASS</8c>
<ITEM ID='82'>,< 1>KWIKSET</1>,< 2>TYLO</2>,< 4a>PRIVACY</4a>,< 7>KNOB</7>,< 8b>SATIN</8b>,< 8c>CHROME</8c>
<ITEM ID='83'>,< 1>KWIKSET</1>,< 8b>POLISHED</8b>,< 8c>BRASS</8c>

while循环读取文件的每一行并单独处理它。然后我们要回显新行,其中cut -d, -f1 <<< "$line"仅提取第一个字段(因为它是静态的)并cut -d, -f2- <<< "$line" | tr ',' '\n' | sort -n | uniq | paste -sd,提取其余字段,对它们进行数字排序,过滤唯一值,并用于paste -sd,重新加入以逗号分隔的列表。

相关内容