2016-04-30 2 views
1

Я хочу написать скрипт в Баш, который печатает наименьшую повторяющуюся строку стандартного вводаИспользование Grep в то время как петля разрывает петлю

Я написал этот код:

#!/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 

программа только входит в цикл один раз, таким образом, он дает плохой OUTPUT

3 id1 

, когда правильный один должен быть

1 square 

Эта линия

tmp=$(grep -c $line) 

похоже t o нарушить цикл, но я не могу понять, почему. Есть ли способ обойти использование grep в моем коде или любой другой способ исправить мой скрипт?

+0

Почему «круг» ваш ожидаемый выход? Это ни последняя повторяющаяся, ни последняя уникальная строка в вашем примере. – tripleee

+0

Это должно быть наименее повторяющееся, а не последнее повторение;) Тем не менее, ваш ответ ниже мне очень помог;) – Konrad

+0

Итак, вы имеете в виду первую уникальную линию? У вас несколько уникальных линий; они все наименее повторяются. – tripleee

ответ

0

Проблема в коде, что это grep

tmp=$(grep -c $line) 

будет читать и стандартного ввода, таким образом, потребляют все линии на самом первом круглый контур, пока выполняется. То есть сначала вы получите read первую строку в $line. Затем вы получите grep для этой строки в остальной части stdin.

Вы можете исправить свой код, используя временный файл, например .:

#!/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 
+0

Спасибо за ваш ответ :) – Konrad

0

Команда grep считывает остальную часть стандартного ввода. Вам нужно будет скопировать вход в временный файл, если вы хотите как grep, так и сделать с ним что-то еще.

Гораздо более простое решение вашей проблемы

uniq -d | tail -n 1 

В целом, работает grep на каждой строке в цикле по файлу находится в антипаттерн, который часто предполагает переезд в Awk или sed вместо этого, если вы можете» t найти простой трубопровод со стандартными инструментами для достижения вашей цели.

+0

Спасибо, ты мне очень помог! – Konrad