仅打印第一列唯一的行

仅打印第一列唯一的行

我正在寻找一种对列表进行排序并打印所有行的方法,其第一列仅出现一次 - 即仅在第一列上匹配。例如,我有一个文件,其中第一列是路径,第二列包含“类型”

/path/foo/1 footsy
/path/foo/1 barsy
/path/foo/X barsy
/path/bar/2 footsy
/path/bar/2 barsy
/path/foo/Y footsy

(文件实际排序为-k1,1)

现在,我只想提取类似的情况

/path/foo/X barsy
/path/foo/Y footsy

我正在考虑使用 awk 的某种方法,我必须存储前一行并将前一行的第一个字段与当前行中的相应字段进行比较。但我还不知道如何完成它:( 我试图适应另一个问题中找到的解决方案,但它并没有真正按希望工作

awk '{
  prev=$0; path=$1; type=$2
  getline
  if ($1 != $path) {
    print prev
  }
}'

答案1

这些答案不需要对输入进行排序:

将计数和最后一行存储在数组中。大文件需要大量内存,并且需要 GNU awk

gawk '
    {count[$1]++; line[$1]=$0} 
    END {
        PROCINFO["sorted_in"]="@val_str_asc"
        for (key in line) if (count[key] == 1) print line[key]
    }
' file

扫描文件两次,首先获取计数,然后打印计数为 1 的行

awk 'NR == FNR {count[$1]++; next} count[$1]==1' file file

这将是最快的并且需要最少的内存,利用排序的输入:

awk '
    prev_key && prev_key != $1 {if (count==1) print prev_line; count=0}
    {prev_key=$1; prev_line=$0; count++}
    END {if (count==1) print prev_line}
' file

答案2

  1. awk通常读取输入的每一行并调用其上的脚本。您将使用的情况getline很少且相距甚远。当您的脚本使用六行输入运行时,以下是所发生情况的概述:

    正常读取第1行

    设置变量
    Call getline,读取第 2 行
    比较变量

    正常读取第3行

    设置变量
    Call getline,读取第 4 行
    比较变量

    正常读取第5行

    设置变量
    Call getline,读取第 6 行
    比较变量

    显然这是行不通的。

  2. 其次,您在代码中犯了一个常见错误awk。在 中awk,输入中的字段被引用为 ,变量被引用为$numbervariable_name。这与 shell 脚本不同,在 shell 脚本中,命令行参数被引用为 ,变量被引用为。您的测试$number$variable_name

    if ($1 != $path)
    

    应该

    if ($1 != path)
    
  3. 你的整体方法是有缺陷的。您无法通过一次查看两行来识别文件中仅出现一次的字符串。我相信您可以通过一次查看三行来做到这一点(即,通过保留变量中的前几行),但是类似的事情变得复杂而混乱。计算出现次数可能更简单。为此,您需要对脚本进行最小的修改。

    awk '{
      if ($1 != path) {
        if (count == 1) {
          print prev
        }
        count=1
      }
      else count++
      prev=$0; path=$1
    }
    END {
        if (count == 1) {
          print prev
        }
    }'
    

    我删除了type,因为你从未使用过它。

    披露:这基本上与格伦答案的最后部分相同。

答案3

如果你的 shell 支持流程替代XandY不包含空格、制表符:

$ grep -Ff <(awk '{print $1" "}' <file | LC_ALL=C uniq -u) <file
/path/foo/X barsy
/path/foo/Y footsy

答案4

你可以尝试用这个:

cat text.tx | sort | uniq -c -w11 | fgrep '1 /' | awk '{print $2" "$3}'

像这样的你的text.txt

]#cat text.txt
/path/foo/1 footsy
/path/foo/1 barsy
/path/foo/X barsy
/path/bar/2 footsy
/path/bar/2 barsy
/path/foo/Y footsy

相关内容