我想在bash中编写一个脚本,用于打印标准输入的最少重复行
我写了这段代码:
#!/bin/bash
var=1000
while read line
do
tmp=$(grep -c $line)
if [ $tmp -lt $var ]
then
var=$tmp
out=$line
fi
done
var="$var $out"
echo $var
但是,例如当使用像这样的测试时
id1
id2
id3
id1
square
id1
id2
id3
id1
circle
id2
id2
程序只进入一次循环,因此输出错误
3 id1
当正确的那个
时1 square
这一行
tmp=$(grep -c $line)
似乎打破了循环,但我找不到原因。 有没有办法绕过在我的代码中使用grep或以其他任何方式修复我的脚本?
答案 0 :(得分:1)
您的代码中存在的问题是此grep
tmp=$(grep -c $line)
将从 stdin 读取,因此在执行while循环的第一轮中消耗所有行。即首先,您将read
第一行$line
。然后,您将在 stdin 的其余部分中grep
获取此字符串。
您可以使用临时文件修复代码,例如:
#!/bin/bash
tmpfile=$(mktemp)
cat > "$tmpfile"
min=0
while IFS= read -r line; do
count=$(grep -c "$line" $tmpfile)
if (( min == 0 || (count < min) )); then
min=$count
out="$min $line"
fi
done < <(sort -u "$tmpfile")
rm "$tmpfile"
echo "$out"
但这当然是非常可怕的解决方案,因为它使用临时文件并多次打开输入文件。更好的是使用类似的东西:
#!/bin/bash
sort | uniq -c | sort -n | head -1
答案 1 :(得分:0)
grep
命令读取标准输入的剩余部分。如果你想同时grep
使用它,你需要将输入复制到临时文件。
解决问题的一个更简单的方法是
uniq -d | tail -n 1
更一般地说,在文件循环中的每一行上运行grep
是反模式的,这通常建议转移到Awk或sed
,如果你找不到一个简单的管道实现目标的标准工具。