我有一个 .txt 文件,其中包含许多名称,每个名称都单独占一行。使用条件 bash,我必须对以下内容回显“是”或“否”:
- 有重复的名字吗?
- .txt 文件中的第一个名称是否也是按字母顺序排列时的第一个名称?
- .txt 文件是否包含特定名称?(如 bash 中所指定)
我尽力了,但甚至无法完成第一个;
if [ sort names.txt | uniq -c > 1]; then echo "Yes"; else echo "No"; fi
我甚至不太清楚这到底起了什么作用。
这一切是怎么做到的?
答案1
您在 Q1 中的尝试存在一些问题:
在
[ ]
测试括号内,>
是普通的输出重定向运算符。(在[[ ]]
扩展测试中,>
是比较运算符,但它比较参数按照字典顺序而不是用数字来表示。)[
和[[
测试对空白很挑剔
综合起来,这些意味着您的命令所做的是1]
在当前目录中创建一个名为的文件,然后抛出一个错误,因为它找不到匹配]
的[
。
sort names.txt | uniq -c
写入标准输出 - 如果你想测试某些东西,你需要使用捕获标准输出命令替换uniq -c
不会产生简单的计数,而是产生多行输出,例如1 bar 2 foo
您可能考虑使用sort | uniq -d
,它仅在存在重复的行时才会产生输出,捕获其输出,并测试结果是否为空字符串:
-z STRING True if string is empty.
-n STRING
STRING True if string is not empty.
例如:
if [ -n "$(sort Names.txt | uniq -d)" ]; then echo "duplicates"; else echo "no duplicates"; fi
或者
if [ -z "$(sort Names.txt | uniq -d)" ]; then echo "unique"; else echo "non unique"; fi
或者,你可以用 替换uniq
来sort -Cu
(悄悄地)检查已排序的文件是否严格排序。在这种情况下,你可以测试管道的退出状态而不是其标准输出:
if sort Names.txt | sort -Cu; then echo "no duplicates"; else echo "duplicates"; fi
对于 Q2 和 Q3,这将取决于文件的格式 - 但您可能会成功使用cut
和grep
或awk
。
答案2
[ sort file | uniq -d ]
将始终读取整个文件。
如果文件很大,即使可能的重复就在最开始,这也可能会非常慢。
您可以使用awk
,这将是很多速度更快。找到第一个重复项后就会停止,无需先对其进行排序。
awk 'seen[$0]++ {print "duplicates"}' file
或更多增强:
awk '
seen[$0]++ {dupes=1; exit}
END {if (dupes) print "duplicates"; else print "no duplicates"}
' file
如果需要将其用作bash
条件的一部分,则可以分配返回值:
awk 'BEGIN{ret=1} seen[$0]++ {ret=0; exit} END{exit ret}' file
例如
if awk 'BEGIN{ret=1} seen[$0]++ {ret=0; exit} END{exit ret}' file; then
echo "duplicates"
else
echo "no duplicates"
fi
关于您的其他问题:
比较第一个词:
if [ "$(sort file | head -n1)" = "$(head -n1 file)" ]; then echo "First line is same as sorted"; fi
检查文件中是否存在特定单词:
if grep -q "specific_word" file; then echo "Found"; fi