
Вопрос 1
я могу использовать
grep -o '^[[:alpha:]_]\+[[:blank:]]*([[:blank:]]*)' /etc/rc.d/init.d/functions
чтобы получить вывод, как показано ниже:
systemctl_redirect ()
checkpid()
__kill_pids_term_kill_checkpids()
__kill_pids_term_kill()
__pids_var_run()
__pids_pidof()
daemon()
killproc()
pidfileofproc()
pidofproc()
status()
echo_success()
echo_failure()
echo_passed()
echo_warning()
update_boot_stage()
success()
failure()
passed()
warning()
action()
strstr()
is_ignored_file()
is_true()
is_false()
apply_sysctl()
И я также хочу узнать, сколько совпадений было найдено, поэтому я использую -c
опцию, на этот раз я получаю только 26
, могу ли я объединить совпавшее содержимое и количество с помощьюgrep
встроенныйварианты? Если нет, то как?
вопрос 2
Я нашел решение на Github для ответа на вопрос 1:
grep -o '^[[:alpha:]_]\+[[:blank:]]*([[:blank:]]*)' /etc/rc.d/init.d/functions \
| tee >(echo -e "\n`wc -l` matched.")
Но вывод часто странный, который выводится после новогоприглашение оболочки!Почему?
решение1
Вы всегда можете сделать:
grep -o ... | awk '{print};END{if (NR) print "\n" NR " matched."}'
Или сделать все это так awk
(что также позволит избежать -o
и \+
GNUизмов):
awk 'match($0, /^[[:alpha:]_]+[[:blank:]]*\([[:blank:]]*\)/) {
print substr($0, RSTART, RLENGTH)
n++
}
END{if (n) print "\n" n " matched.")'
или perl
:
perl -lne 'for (/^\w+\h*\(\h*\)/g) {print; $n++}
END {print "\n$n matched." if $n}'
(обратите внимание, что в этом случае \w
ограничивается буквами ASCII, добавьте , -Mopen=locale
чтобы включить любую букву в любом алфавитном сценарии в соответствии с локалью, как в подходах grep
или awk
(некоторых awk
)
Что касается вашего вопроса 2, это потому, что bash
(в отличие от zsh
) не ждет команд, запущенных в процессе подстановки, вызывая такого рода проблемы. СмотритеВывод замещения процесса не соответствует порядкуБольше подробностей.
решение2
Вместо того, чтобы tee
использовать такой инструмент, какpee
:
grep -o '^[[:alpha:]_]\+[[:blank:]]*([[:blank:]]*)' /etc/rc.d/init.d/functions |
pee cat 'sleep 1; echo -e "\n`wc -l` matched."'
Если pee
он недоступен, это можно сделать с помощью отдельной bash
оболочки и отключить ее подсказки с помощью unset
и shopt
:
bash -c \
"unset PS0 PS1 PS2 PS3
shopt -u promptvars
grep -o '^[[:alpha:]_]\+[[:blank:]]*([[:blank:]]*)' \
/etc/rc.d/init.d/functions |
tee >( sleep 1s; printf '\n%s matched.' `wc -l`; )
sleep 2s"
Общие ответы:
Невозможно сделать с одним экземпляром
grep
.Чтобы получить полный подсчет, когда в строке есть более одного совпадения
grep -o
, используйтеwc -l
:printf "foo bar baz\nbuz biz\n" | grep -o 'b[^ ]*' | wc -l
Выход:
4
Если требуется префиксное количество, используйте
nl
, (илиcat -n
):printf "foo bar baz\nbuz biz\n" | grep -o 'b[^ ]*' | nl
Выход:
1 bar 2 baz 3 buz 4 biz
С параллельными процессами,то есть
tee >(echo -e "\n`wc -l` matched.")
нет гарантии, какой процесс завершится первым. Иногда можно добавить небольшую задержку, чтобы застраховать заказ.
Печать параллельно "фу" будет первый "уф" после задержки в 1 секунду:
echo foo | tee >(sleep 1s; rev)
Печать параллельно "уф" будет первый "фу" после задержки в 1 секунду:
echo foo | tee >(rev) >(sleep 1s;cat) > /dev/null