Вы можете использовать Grep, но вы должны использовать его в два раза. (Вы не можете использовать один grep, потому что ERE не имеет возможности отрицать строку, вы можете только отменить выражение в скобках, которое будет соответствовать одиночным символам.)
Ниже приведено тестирование GNU grep v2.5.1, где вы можете использовать \<
и \>
как (возможно, непереносимых) разделители слов:
$ word="ab"
$ < input.txt egrep "(\<$word\>.*){3}" | egrep -v "(\<$word\>.*){4}"
abc ab cds ab abcd edfs ab
abcdefghijklmnop ab cdab ab ab
$ < input.txt egrep "(\<$word\>.*){2}" | egrep -v "(\<$word\>.*){3}"
kkmd ab jnabc bad ab
идея заключается в том, что мы извлечем из наших входных линий файлов с N вхождений слова, затем убирается из этого результата любой строк с N + 1 вхождениями. Конечно, строки с наименьшим количеством N не совпадают с первым grep.
Или, вы можете также сделать это в чистом Баш, если вы чувствуете себя немного мазохистом:
$ word="ab"; num=3
$ readarray lines < input.txt
$ for this in "${lines[@]}"; do declare -A words=(); x=($this); for y in "${x[@]}"; do ((words[$y]++)); done; [ "0${words[$word]}" -eq "$num" ] && echo "$this"; done
abc ab cds ab abcd edfs ab
abcdefghijklmnop ab cdab ab ab
Разразившийся для облегчения чтения (или сценариев):
#!/usr/bin/env bash
# Salt to taste
word="ab"; num=3
# Pull content into an array. This isn't strictly necessary, but I like
# getting my file IO over with quickly if possible.
readarray lines < input.txt
# Walk through the array (or you could just walk through the input file)
for this in "${lines[@]}"; do
# Initialize this line's counter array
declare -A words=()
# Break up the words into array elements
x=($this)
# Step though the array, counting each unique word
for y in "${x[@]}"; do
((words[$y]++))
done
# Check the count for "our" word
[ "0${words[$word]}" -eq $num ] && echo "$this"
done
Разве это не было весело? :)
Но это awk
вариант имеет больше смысла для меня. Это портативный однострочный динамик, который не зависит от GNU awk (поэтому он будет работать в OS X, BSD и т. Д.)
Это работает путем создания ассоциативного массива для подсчета слов в каждой строке, а затем напечатать строку, если счетчик для «интересных» слов, что определяется как num
. Это та же основная концепция, что и сценарий bash выше, но awk позволяет нам делать это намного лучше. :)
Если вы используете 'sed' или' awk', вам не нужно зацикливать файл. Это то, что эти языки делают в любом случае. – pfnuesel
@pfnuesel я знаю, но я не знал другого способа проверить строку за строкой – Papanash
Это то, что делает 'sed', проверяя линию за строкой. – pfnuesel