BASH - 判断是否存在重复行(y / n)

时间:2014-03-18 23:07:52

标签: bash file uniq

我正在编写一个脚本来操作文本文件。

我要做的第一件事是检查是否存在重复的条目,如果存在,请询问用户是否要保留或删除它们。

我知道如果它们存在,如何显示重复的行,但我想要学习的只是得到“是否存在重复项?”这个问题的是/否答案。

如果找到重复项,只要命令完成没有问题,uniq似乎会返回0

我可以在if语句中添加什么命令,只是为了告诉我是否存在重复的行?

我的文件非常简单,只是单列中的值。

4 个答案:

答案 0 :(得分:5)

我可能会使用awk来做这件事但是,为了多样化,这里有一个简短的管道来完成同样的事情:

$ { sort | uniq -d | grep . -qc; } < noduplicates.txt; echo $?
1
$ { sort | uniq -d | grep . -qc; } < duplicates.txt; echo $?
0

sort + uniq -d确保只有重复的行(不必相邻)打印到stdoutgrep . -c计算这些行wc -l 1}}带有有用的副作用,如果它不匹配(即零计数),它返回1-q只是静音输出,所以它不会打印行数,所以你可以在脚本中静默使用它。

has_duplicates()
{
  {
    sort | uniq -d | grep . -qc
  } < "$1"
}

if has_duplicates myfile.txt; then
  echo "myfile.txt has duplicate lines"
else
  echo "myfile.txt has no duplicate lines"
fi

答案 1 :(得分:3)

您可以将awk与布尔||运算符结合使用:

# Ask question if awk found a duplicate
awk 'a[$0]++{exit 1}' test.txt || (
    echo -n "remove duplicates? [y/n] "
    read answer
    # Remove duplicates if answer was "y" . I'm using `[` the shorthand
    # of the test command. Check `help [`
    [ "$answer" == "y" ] && uniq test.txt > test.uniq.txt
)

||之后的块只有在awk命令返回1时才会被执行,这意味着它找到了重复项。

但是,为了基本了解,我还会展示一个使用if块的示例

awk 'a[$0]++{exit 1}' test.txt

# $? contains the return value of the last command
if [ $? != 0 ] ; then
    echo -n "remove duplicates? [y/n] "
    read answer
    # check answer
    if [ "$answer" == "y" ] ; then
        uniq test.txt > test.uniq.txt            
    fi
fi

然而[] 只是括号,就像在其他编程语言中一样。 [test bash内置命令和]最后一个参数的同义词。您需要阅读help [才能理解

答案 2 :(得分:1)

你可以使用这个awk one-liner执行uniq=yes/no

awk '!seen[$0]{seen[$0]++; i++} END{print (NR>i)?"no":"yes"}' file
  • awk使用名为seen的唯一数组。
  • 每次我们将元素置于唯一中时,我们会增加一个计数器i++
  • 最后在END块中,我们将此记录中的记录数与此代码中的唯一记录数进行比较:(NR>i)?
  • 如果条件为真,则表示存在重复记录,我们打印no否则会打印yes

答案 3 :(得分:1)

快速bash解决方案:

#!/bin/bash

INPUT_FILE=words

declare -A a 
while read line ; do
    [ "${a[$line]}" = 'nonempty' ] && duplicates=yes && break
    a[$line]=nonempty
done < $INPUT_FILE

[ "$duplicates" = yes ] && echo -n "Keep duplicates? [Y/n]" && read keepDuplicates

removeDuplicates() {
    sort -u $INPUT_FILE > $INPUT_FILE.tmp
    mv $INPUT_FILE.tmp $INPUT_FILE
}

[ "$keepDuplicates" != "Y" ] && removeDuplicates

脚本从INPUT_FILE逐行读取,并将关联数组a中的每一行存储为键,并将字符串nonempty设置为值。在存储值之前,它首先检查它是否已经存在 - 如果它存在意味着它找到了重复项并且它设置了duplicates标志然后它就会突破循环。

稍后它只检查是否设置了标志并询问用户是否保留重复项。如果他们回答Y以外的任何内容,则会调用removeDuplicates函数,该函数使用sort -u删除重复项。 ${a[$line]}计算关键字a的关联数组$line的值。 [ "$duplicates" = yes ]是用于测试的bash内置语法。如果测试成功,则评估&&之后的任何内容。

但请注意,awk解决方案可能会更快,因此如果您希望处理更大的文件,可能需要使用它们。