Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/loops/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Bash 在while循环中使用grep会中断循环_Bash_Loops_Grep - Fatal编程技术网

Bash 在while循环中使用grep会中断循环

Bash 在while循环中使用grep会中断循环,bash,loops,grep,Bash,Loops,Grep,我想在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 squar

我想在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,或以任何其他方式修复我的脚本?

命令读取标准输入的其余部分。如果既要
grep
输入,又想对其执行其他操作,则需要将输入复制到临时文件中

解决问题的一个更简单的方法是

uniq -d | tail -n 1

更一般地说,在文件上循环的每一行上运行
grep
是反模式的,如果您无法找到使用标准工具实现目标的简单管道,则通常建议移动到Awk或
sed

代码中的问题是这
grep

将从stdin读取数据,从而在执行while循环的第一轮上消耗所有行。即,首先,您将
将第一行读入
$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"

为什么
circle
是您的预期输出?它既不是示例中的最后一个重复行,也不是最后一个唯一行。它应该是重复最少的,而不是最后一个重复;)不过,你下面的回答对我帮助很大;)那么,你是说第一条独特的线路吗?你有多个独特的行;不,我想我的英语技能没有让我说得足够清楚,如果标准中有唯一的一行,它也应该打印出来,假设我们有一行包含单词:正方形,两行包含单词:圆形,三行包含单词:三角形。它应该打印“square”,因为它在文件中只出现一次(出现的次数最少),这一点很清楚,但是如果每个文件都有三次,你只想要第一次吗?谢谢,你帮了我很多忙!谢谢你的回答:)
#!/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