假设我有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
答案 0 :(得分:4)
如果我理解你的问题,那么
sort repeat_lines.txt | uniq -u
应该可以解决问题。
e.g。对于包含以下内容的文件:
a
b
a
c
b
它将输出c
。
如需进一步参考,请参阅sort manpage,uniq manpage。
答案 1 :(得分:1)
您使用标准shell工具sort
和uniq
得到了合理的答案。这可能是您想要使用的解决方案,如果您想要便携式且不需要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" )'
我们在这里做的是:
declare -A
创建关联数组。这是我提到的bash 4功能。while
循环读取文件的每一行,并递增一个计数器,该计数器使用文件行的内容作为关联数组中的键。for
循环遍历数组,删除计数器大于1的任何元素。declare -p
以可预测,可重复使用的格式打印数组的详细信息。您可以使用另一个for
循环来逐步浏览剩余的数组元素(其中可能只有一个),以便对它们执行某些操作。请注意,此解决方案虽然适用于小文件(例如,最多几千行),但对于非常大的文件(例如数百万行)可能无法很好地扩展。 Bash不是以这种方式读取输入的最快速度,并且在使用数组时必须认识到内存限制。
sort
替代方案具有内存优化的优势,使用磁盘上的文件来处理超大文件,但代价是速度。
如果您处理的文件只有几百行,那么很难预测哪种解决方案会更快。最后,输出形式可能决定了您选择的解决方案。 sort | uniq
管道生成标准输出列表。上面的bash解决方案生成与数组中的键相同的列表。否则,它们在功能上是等价的。