如何在每行输入中找到唯一字符?

时间:2015-08-21 04:44:03

标签: bash awk sed grep

有没有办法提取每一行的唯一字符?

我知道我可以使用

找到文件的唯一行
sort -u file

我想确定每一行的唯一字符(类似sort -u每行)。

澄清:给出此输入:

111223234213
111111111111
123123123213
121212122212

我想得到这个输出:

1234
1
123
12

7 个答案:

答案 0 :(得分:5)

使用sed

sed ':;s/\(.\)\(.*\)\1/\1\2/;t' file

它的基本功能是捕捉一个角色并检查它是否出现在该线的其他任何位置。它还捕获了这些之间的所有字符。 然后它取代所有这些,包括刚出现的第二次发生,然后是中间的发生。

如果上一个命令成功,则

t进行测试并跳转到:标签。然后重复此操作直到s///命令失败,这意味着只保留唯一字符。

;只是分开命令。

1234
1
123
12

保持秩序。

答案 1 :(得分:3)

它没有按照原始顺序得到东西,但是这个awk单行程似乎有效:

awk '{for(i=1;i<=length($0);i++){a[substr($0,i,1)]=1} for(i in a){printf("%s",i)} print "";delete a}' input.txt

分开以便于阅读,它可以像这样独立:

#!/usr/bin/awk -f

{
  # Step through the line, assigning each character as a key.
  # Repeated keys overwrite each other.
  for(i=1;i<=length($0);i++) {
    a[substr($0,i,1)]=1;
  }

  # Print items in the array.
  for(i in a) {
    printf("%s",i);
  }

  # Print a newline after we've gone through our items.
  print "";

  # Get ready for the next line.
  delete a;
}

当然,同样的概念也可以在纯粹的bash中轻松实现:

#!/usr/bin/env bash

while read s; do
  declare -A a
  while [ -n "$s" ]; do
    a[${s:0:1}]=1
    s=${s:1}
  done
  printf "%s" "${!a[@]}"
  echo ""
  unset a
done < input.txt

请注意,由于关联数组,这取决于bash 4。而这个确实以原始顺序获取内容,因为bash在保持数组键的顺序方面比awk更好。

我认为你使用Jose的sed得到了一个解决方案,尽管它有一堆额外的管道配件。 :)

您提到的最后一个工具是grep。我很确定你不能在传统的grep中做到这一点,但也许一些勇敢的灵魂可能能够使用grep -P构建一个perl-regexp变体(即-o)并使用外观。他们现在需要的咖啡比我现在多。

答案 2 :(得分:3)

另一种解决方案,

while read line; do 
  grep -o . <<< $line | sort -u | paste -s -d '\0' -;
done < file

grep -o .转换&#39;行行&#39;到“&#39;列线&#39;
sort -u排序字母并删除重复字母
paste -s -d '\0' -转换&#39;列线&#39;到排行&#39;
-作为要粘贴的文件名参数,告诉它使用标准输入。

答案 3 :(得分:3)

使用的一种方式:

**Dealer Code        Email**
T04292            a@gmail.com
T04292            a@gmail.com
T02119            b@gmail.com
T01125            b@gmail.com
RS0009            c@gmail.com
RS0001            c@gmail.com
C01020            d@gmail.com

结果:

perl -F -lane 'print do { my %seen; grep { !$seen{$_}++ } @F }' file

答案 4 :(得分:1)

这个awk应该可以工作:

awk -F '' '{delete a; for(i=1; i<=NF; i++) a[$i]; for (j in a) printf "%s", j; print ""}' file
1234
1
123
12

下面:

-F ''将通过char打破记录字符,在$1$2等中为我们提供单个字符。

注意:对于非gnu awk使用:

awk 'BEGIN{FS=""} {delete a; for(i=1; i<=NF; i++) a[$i]; 
        for (j in a) printf "%s", j; print ""}' file

答案 5 :(得分:1)

这可能适合你(GNU sed):

sed 's/\B/\n/g;s/.*/echo "&"|sort -u/e;s/\n//g' file

将每一行拆分为一系列行。独特排序那些线条。将结果合并为一行。

答案 6 :(得分:0)

使用sed和gnu工具的唯一和排序的替代方案:

sed 's/\(.\)/\1\n/g' file | sort | uniq

每行产生一个字符;如果您想要一行,请执行以下操作:

sed 's/\(.\)/\1\n/g' file | sort | uniq | sed ':a;N;$!ba;s/\n//g;'

这样做的好处是可以按排序顺序显示字符,而不是显示顺序。