查找仅在文件中显示一行的行

时间:2018-01-02 17:40:35

标签: linux bash file

假设我有100行文件。在文件中有很多行重复自己,只有一行不重复。

我想找到只显示一次的行。是否有一个命令,或者我必须构建一个复杂的循环,如下所示?

到目前为止我的代码:

#!/bin/bash
filename="repeat_lines.txt"

var="$(wc -l <$filename )"
echo "length:" $var
#cp ex4.txt ex4_copy.txt
for((index=0; index < var; index++));
do
    one="$(head -n $index $filename | tail -1)"
    counter=0
        for((index2=0; index2 < var; index2++));
        do
            two="$(head -n $index2 $filename | tail -1)"
            if [ "$one" == "$two" ]; then
                counter=$((counter+1))
            fi
        done
    echo $one"is "$counter" times in the text: "
done

2 个答案:

答案 0 :(得分:4)

如果我理解你的问题,那么

sort repeat_lines.txt | uniq -u应该可以解决问题。

e.g。对于包含以下内容的文件:

a
b
a
c
b

它将输出c

如需进一步参考,请参阅sort manpageuniq manpage

答案 1 :(得分:1)

您使用标准shell工具sortuniq得到了合理的答案。这可能是您想要使用的解决方案,如果您想要便携式且不需要bash的东西。

但另一种方法是使用内置于bash shell中的功能。一种方法可能是使用关联数组,这是bash 4及更高版本的一个特性。

$ cat file.txt
a
b
c
a
b
$ declare -A lines
$ while read -r x; do ((lines[$x]++)); done < file.txt
$ for x in "${!lines[@]}"; do [[ ${lines["$x"]} -gt 1 ]] && unset lines["$x"]; done
$ declare -p lines
declare -A lines='([c]="1" )'

我们在这里做的是:

  1. declare -A创建关联数组。这是我提到的bash 4功能。
  2. while循环读取文件的每一行,并递增一个计数器,该计数器使用文件行的内容作为关联数组中的键。
  3. for循环遍历数组,删除计数器大于1的任何元素。
  4. declare -p以可预测,可重复使用的格式打印数组的详细信息。您可以使用另一个for循环来逐步浏览剩余的数组元素(其中可能只有一个),以便对它们执行某些操作。
  5. 请注意,此解决方案虽然适用于小文件(例如,最多几千行),但对于非常大的文件(例如数百万行)可能无法很好地扩展。 Bash不是以这种方式读取输入的最快速度,并且在使用数组时必须认识到内存限制。

    sort替代方案具有内存优化的优势,使用磁盘上的文件来处理超大文件,但代价是速度。

    如果您处理的文件只有几百行,那么很难预测哪种解决方案会更快。最后,输出形式可能决定了您选择的解决方案。 sort | uniq管道生成标准输出列表。上面的bash解决方案生成与数组中的键相同的列表。否则,它们在功能上是等价的。