【问题标题】:Linux join utility complains about input file not being sortedLinux join 实用程序抱怨输入文件未排序
【发布时间】:2014-10-15 09:39:00
【问题描述】:

我有两个文件:

file1 的格式为:

field1;field2;field3;field4

(file1 最初未排序)

file2 的格式为:

field1

(文件2已排序)

我运行以下 2 个命令:

sort -t\; -k1 file1 -o file1 # to sort file 1
join -t\; -1 1 -2 1 -o 1.1 1.2 1.3 1.4 file1 file2

我收到以下消息:

join: file1:27497: is not sorted: line_which_was_identified_as_out_of_order

为什么会这样?

(我还尝试对 file1 进行排序,考虑到整行,不仅是该行的第一个字段,但没有成功)

sort -t\; -c file1 不输出任何内容。在第 27497 行附近,情况确实很奇怪,这意味着 sort 没有正确完成它的工作:

              XYZ113017;...
line 27497--> XYZ11301;...
              XYZ11301;...

【问题讨论】:

  • join 非常挑剔。 sort -t\; -c file1 说什么?排序文件的第 27497 行周围是什么? (请update您的问题提供这些详细信息。)
  • 请查看我更新的问题

标签: linux bash sorting join text-processing


【解决方案1】:

sort -k1 使用从字段 1 开始的所有字段作为键。您需要指定一个停止字段。

sort -t\; -k1,1

【讨论】:

  • 我按照你的建议做了,我遇到了完全相同的问题
  • 你能把第 27497 行周围的 3 行复制到一个单独的文件中,然后在上面运行sort --debug -t\; -k1,1,看看它选择了什么顺序以及为什么?
  • 调试输出显示 sort 正确识别了排序字段。仍然,它说:113017 出现在 11301 之前,事实并非如此
  • 试试这个方法:LC_ALL=C sort --debug -s -t\; -k1,1 your3linefile
  • join 手册页推荐使用 -k 1b,1 作为排序键。如果有任何前导空格,b 会有所不同。
【解决方案2】:

用更广阔的视角补充Wumpus Q. Wumbley's helpful answer(因为我发现这篇文章研究了一个稍微不同的问题)。

  • 使用join时,输入文件必须仅按连接字段排序,否则您可能会看到由OP。

在对输入文件进行排序时,错误地包含了两个常见的情况,其中更多包括:

  • 如果您确实指定了一个字段,那么很容易忘记您还必须指定一个 stop 字段 - 即使您只定位 1 字段 - 因为sort 使用该行的剩余部分,如果只指定了一个 start 字段;例如:

    • sort -t, -k1 ... # !! FROM field 1 THROUGH THE REST OF THE LINE
    • sort -t, -k1,1 ... # Field 1 only
  • 如果您的排序字段是输入中的第一个字段,则可能根本不指定任何字段选择器。

    • 但是,如果字段值可以是彼此的前缀子字符串,对整行进行排序将不会(必然)导致与仅按第一个字段排序的排序顺序相同:
    • sort ... # NOT always the same as 'sort -k1,1'! see below for example

陷阱示例:

#!/usr/bin/env bash

# Input data: fields separated by '^'.
# Note that, when properly sorting by field 1, the order should
# be "nameA" before "nameAA" (followed by "nameZ").
# Note how "nameA" is a substring of "nameAA".
read -r -d '' input <<EOF
nameA^other1
nameAA^other2
nameZ^other3
EOF

# NOTE: "WRONG" below refers to deviation from the expected outcome
#       of sorting by field 1 only, based on mistaken assumptions.
#       The commands do work correctly in a technical sense.

echo '--- just sort'
sort <<<"$input" | head -1 # WRONG: 'nameAA' comes first

echo '--- sort FROM field 1'
sort -t^ -k1 <<<"$input" | head -1 # WRONG: 'nameAA' comes first

echo '--- sort with field 1 ONLY'
sort -t^ -k1,1 <<<"$input" | head -1 # ok, 'nameA' comes first

解释:

  • 当不限制排序到第一个字段时,它是字符的相对排序顺序。 ^ 和 A(列索引 6)在此示例中很重要。换句话说:字段分隔符与数据进行比较,这就是问题的根源:^ 的 ASCII 值比 A 更高,因此排序 在之后> 'A',导致以nameAA^ 开头的行排在nameA^ 之前。

  • 注意:问题可能会出现在 one 平台上,但会在 another 上被掩盖,具体取决于语言环境和字符集使用的设置和/或sort 实现;例如,使用en_US.UTF-8 的区域设置,, 作为分隔符,- 允许在内部字段:

    • sort 用于 OSX 10.10.2(old GNU sort 版本,5.93)将 , 排序在 - 之前(与 ASCII 值一致)
    • sort 在 Ubuntu 14.04 (GNU sort 8.21) 上使用 相反:在 , 之前排序 -[1]

[1] 我不知道为什么 - 如果有人知道,请告诉我。使用sort &lt;&lt;&lt;$'-\n,'进行测试

【讨论】:

    【解决方案3】:

    ... 或者 gnu 排序和所有其他 GNU 命令一样有缺陷

    尝试对 Gi1/0/11 与 Gi1/0/1 进行排序,您将永远无法获得适合连接输入的实际常规文本排序,因为有人在排序中添加了一些额外的智能,很乐意使用数字或人类在这种情况下自动进行数字排序,甚至无需添加标志来强制执行常规行为

    适合人类的东西很少适合脚本

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-03-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多