Как я могу использовать grep для получения количества каналов ('|')?
-
03-07-2019 - |
Вопрос
Я пытался:
grep -c "\|" *.*
Но это не сработало, так как дает неверное количество последовательных каналов.
Как я могу этого добиться?
Решение
Другой вариант, использующий Perl:
perl -e 'while(<>){$c+=tr/|/|/};print "$c\n"' *
В формате не одной строки это:
while(<>){
$c += tr/|/|/
}
print "$c\n"
Строка while(<>){
- это магия Perl для чтения строк из файлов команды или из STDIN
. Вы привыкаете к этому через некоторое время. Сама строка переходит в переменную с именем $_
, которая является параметром по умолчанию для многих команд Perl. Например, tr
, который работает почти так же, как tr(1)
, по умолчанию работает на $c
. Я помещаю свои результаты в глобальную переменную my $c = 0;
. (В полной программе лучше объявить ее лексической переменной с +=
вне цикла.) Оператор *.*
добавляет результат команды <=> (количество символов канала в данном случае) к текущему значение <=>.
Просто использовать <=> - это явно более простой вариант. ; -) р>
Использование <=> - это DOSism, который вы вряд ли захотите использовать на UNIX-подобной платформе.
Использование одинарных кавычек, чтобы оболочка не интерпретировала символ канала, читается немного лучше. Например, я проверил свой ответ с помощью:
$ echo '||||
|||||' | perl -e 'while(<>){$c+=tr/|/|/};print "$c\n"'
9
Другие советы
Вы можете использовать tr(1)
, чтобы удалить все непузырьковые символы, а затем использовать wc(1)
, чтобы получить общее количество:
cat *.* | tr -d -c '|' | wc -c
Это нелогично, но в большинстве регулярных выражений Unix экранирование |
делает его оператором or. Таким образом, ваша строка фактически соответствует & Quot; ничто или ничто & Quot; (Вы можете проверить это, добавив несколько вариантов с обеих сторон). Просто используйте
grep -c "|" *.*
Во-вторых, grep считает строки, а не символы. Вы можете использовать другой инструмент; или, если вы настаиваете на grep, вы можете поставить каждый " | " на своей собственной линии. Например, с помощью sed:
sed 's/|/|\n/g' *.*
Примечание: если вы используете sed, я советую много тестирования, чтобы убедиться, что он делает то, что вы думаете. Мне нужно было именно тогда.
Наконец, объедините ингредиенты:
cat *.* | sed 's/|/|\n/g' | grep -c "|"
К сожалению, это может не сработать, так как вы, вероятно, не используете unix (из-за *.*
). Но, надеюсь, это объясняет проблему, которую я всегда нахожу странно обнадеживающей.
Если вы хотите найти несколько каналов, то
fgrep -o "|" | wc -l
Если вы хотите найти количество строк хотя бы с одним каналом,
fgrep -c "|"
попробуй
grep -c "\|" *.*
и прочтите несколько руководств по bash