Это - старый вопрос, но любопытный, другие могут рассмотреть команду newusers
. Это присутствует и в системе RHEL5.5 и в системе Ubuntu 12.04, которую я использую, таким образом, я взял бы предположение, это будет доступно в репозиториях для большинства дистрибутивов.
От man newusers
:
Команда newusers читает файл пар имени пользователя и пароля в виде открытого текста и использует эту информацию, чтобы обновить группу существующих пользователей или создать новых пользователей. Каждая строка находится в том же формате как стандартный файл паролей (см. passwd (5)) за исключениями, объясненными ниже
tac
только помогает, если Вы также используете grep -m 1
(принятие GNU grep
) иметь grep
остановитесь после первого соответствия:
tac accounting.log | grep -m 1 foo
От man grep
:
-m NUM, --max-count=NUM
Stop reading a file after NUM matching lines.
В примере в Вашем вопросе, обоих tac
и grep
должен обработать весь файл, настолько использующий tac
довольно бессмысленно.
Так, если Вы не используете grep -m
, не использовать tac
вообще просто проанализируйте вывод grep
получить последнее соответствие:
grep foo accounting.log | tail -n 1
Другой подход должен был бы использовать Perl или любой другой язык сценариев. Например (где $pattern=foo
):
perl -ne '$l=$_ if /foo/; END{print $l}' file
или
awk '/foo/{k=$0}END{print k}' file
Причина, почему
tac file | grep foo | head -n 1
не останавливается в первом соответствии, из-за буферизации.
Обычно, head -n 1
выходы после чтения строки. Так grep
должен получить SIGPIPE и выход, а также скоро поскольку он пишет свою вторую строку.
Но то, что происходит, является этим, потому что его вывод не идет в терминал, grep
буферы это. Таким образом, это не пишет это, пока это не накопилось достаточно (4 096 байтов в моем тесте с GNU grep).
То, что это означает, является этим grep
не выйдет, прежде чем это записало 8 192 байта данных, так вероятно, довольно много строк.
С GNU grep
, можно заставить его выйти раньше при помощи --line-buffered
который говорит этому писать строки, как только они найдены независимо от того, переходит ли к терминалу или нет. Так grep
затем вышел бы на вторую строку, которую это находит.
Но с GNU grep
так или иначе можно использовать -m 1
вместо этого, поскольку @terdon показал, который лучше, поскольку он выходит в первом соответствии.
Если Ваш grep
не GNU grep
, затем можно использовать sed
или awk
вместо этого. Но tac
будучи командой GNU, я сомневаюсь, что Вы найдете систему с tac
где grep
не GNU grep
.
tac file | sed "/$pattern/!d;q" # BRE
tac file | P=$pattern awk '$0 ~ ENVIRON["P"] {print; exit}' # ERE
Некоторые системы имеют tail -r
сделать то же самое как GNU tac
делает.
Обратите внимание что для регулярных (seekable) файлов, tac
и tail -r
эффективны, потому что они действительно читают файлы назад, они только читают файл полностью в памяти прежде, чем распечатать его назад (как подход sed @slm или tac
на нерегулярных файлах был бы).
В системах, где ни один tac
ни tail -r
доступны, единственные опции состоят в том, чтобы реализовать чтение в обратном направлении вручную с языками программирования как perl
или использование:
grep -e "$pattern" file | tail -n1
Или:
sed "/$pattern/h;$!d;g" file
Но они означают находить все соответствия и только печатают последнее.
Вот возможное решение, которое найдет местоположение первого вхождения шаблона от в последний раз:
tac -s "$pattern" -r accounting.log | head -n 1
Это использует -s
и -r
переключатели tac
которые являются следующие:
-s, --separator=STRING
use STRING as the separator instead of newline
-r, --regex
interpret the separator as a regular expression
Показ некоторых альтернативных методов к прекрасному использованию ответа @Terdon sed
:
$ sed '1!G;h;$!d' file | grep -m 1 $pattern
$ sed -n '1!G;h;$p' file | grep -m 1 $pattern
$ seq 10 > file
$ sed '1!G;h;$!d' file | grep -m 1 5
5
$ sed -n '1!G;h;$p' file | grep -m 1 5
5
В качестве награды вот немного более легкая нотация в Perl для запоминания:
$ perl -e 'print reverse <>' file | grep -m 1 $pattern
$ perl -e 'print reverse <>' file | grep -m 1 5
5
sed
один), вероятно, чтобы быть несколькими порядками величины медленнее, чем grep 5 | tail -n1
или sed '/5/h;$!d;g'
. Это будет также потенциально использовать большую память. Это не намного более портативно, поскольку Вы все еще используете GNU grep -m
.
– Stéphane Chazelas
04.02.2014, 13:26
tac
, моя точка была то, что это не помогает, если Вы также не используете-m
так как файл все еще должен быть считан полностью двумя программами. Иначе Вы могли просто искать все происшествия и сохранить только последнее, как я делаю сtail -n 1
. большое спасибо – terdon♦ 02.02.2014, 19:49grep -m
, это должно быть довольно эффективно. – camh 04.02.2014, 10:16grep -m
это. OP не использовал-m
так и grep и tac обрабатывали все это. – terdon♦ 04.02.2014, 15:57