我正在编写一个操作文本文件的脚本。
我想做的第一件事是检查是否存在重复条目,如果存在,请询问用户我们是要保留还是删除它们。
如果存在重复行,我知道如何显示,但我想学习的只是得到"是否存在重复行?"问题的是/否答案
似乎uniq
将返回0
,无论是在发现重复的情况下,还是在命令没有问题的情况下完成。
我可以在if
-语句中输入什么命令来告诉我是否存在重复行?
我的文件非常简单,它只是单列中的值。
我可能会使用awk
来完成这项工作,但为了多样化,这里有一个简单的管道来完成同样的事情:
$ { sort | uniq -d | grep . -qc; } < noduplicates.txt; echo $?
1
$ { sort | uniq -d | grep . -qc; } < duplicates.txt; echo $?
0
sort
+uniq -d
确保只有重复的行(不必相邻(被打印到stdout
,grep . -c
计算那些模仿wc -l
的行,有用的副作用是,如果不匹配(即零计数(,它会返回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
您可以将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 [
才能理解
一个快速的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
来删除重复项。CCD_ 27评估为关键字CCD_ 29的关联数组CCD_。[ "$duplicates" = yes ]
是用于测试的bash内置语法。如果测试成功,则评估&&
之后的任何情况。
但请注意,awk解决方案可能会更快,因此如果您希望处理更大的文件,则可能需要使用它们。
您可以使用以下awk一行代码执行uniq=yes/no
:
awk '!seen[$0]{seen[$0]++; i++} END{print (NR>i)?"no":"yes"}' file
- awk使用一个名为
seen
的unique数组 - 每次我们将一个元素放入unique中时,我们都会增加一个计数器
i++
- 最后,在
END
块中,我们将记录数与此代码中唯一的记录数进行比较:(NR>i)?
- 如果条件为true,则表示存在重复的记录,并且我们打印
no
,否则它将打印yes