#shell
#оболочка
Вопрос:
Используя оболочку, я хочу искать и печатать только вложенную строку со следующим словом к этой вложенной строке.
например, в файле журнала есть строка «сегодня понедельник, и это: 1234, так что я нахожусь».
if grep -q "this is :" ./logfile; then
#here i want to print only sub-string with next word i.e. "this is:1234"
#echo ???
fi
Комментарии:
1. Какой длины файл? Если он короткий, может быть быстрее выполнить этот поиск в собственной оболочке, а не создавать внешние инструменты (
grep
,sed
,awk
, и т. Д.), Хотя эти инструменты, Как правило, будут обрабатывать содержимое быстрее, как только стоимость их запуска будет оплачена.2. Кстати, внешний
if grep -q
, возможно, плохая идея — означает, что вы читаете файл дважды, один раз, чтобы проверить его содержимое, а затем снова, чтобы прочитать его содержимое. Если вы собираетесь запустить внешнюю команду, лучше использоватьif result=$(that-command); then ...
как для захвата вывода, так и для проверки состояния выхода за один проход. Если команда не устанавливает статус выхода в зависимости от того, есть ли совпадение, этоif result=$(that-command) amp;amp; [ -n "$result" ]; then
может иметь больше смысла.
Ответ №1:
Вы можете использовать sed
with 1
для отображения соответствующей строки в (..)
:
sed 's/.*(this is:[0-9a-zA-Z]*).*/1/' logfile
РЕДАКТИРОВАТЬ: приведенная выше команда подходит только для ввода в 1 строку.
Когда у вас есть файл с большим количеством строк, вы хотите печатать только те строки, которые совпадают:
sed -n 's/.*(this is:[0-9a-zA-Z]*).*/1/p' logfile
Если у вас большой файл и вы хотите увидеть только первое совпадение, вы можете объединить эту команду с head -1
, но вы хотели бы остановить сканирование / синтаксический анализ после первого совпадения. Вы можете использовать q
для выхода, но вы хотите выйти только после совпадения.
sed -n '/.*(this is:[0-9a-zA-Z]*).*/{s//1/p;q}'
Комментарии:
1. Если бы вы изменили это, чтобы также исключить все остальные строки и выйти после нахождения совпадения, я бы подумал, что мы были бы настроены.
Ответ №2:
Вы можете использовать регулярное выражение с предварительным просмотром, если вам нужно только следующее слово:
$ grep --perl-regexp -o '(?<=(this is:))(S )' ./logfile
1234
Если вы хотите оба, то просто:
$ grep --perl-regexp -o 'this is:S ' ./logfile
this is:1234
-o
Опция указывает grep
возвращать только соответствующую часть.
В приведенных выше командах мы предполагали, что «слово» представляет собой последовательность символов, не содержащих пробелов. Вы можете настроить это в соответствии с вашими потребностями.
Ответ №3:
Если у вас есть система с расширениями GNU (но вы не уверены, что она была скомпилирована с дополнительной поддержкой PCRE), рассмотрите:
if result=$(grep -E -m 1 -o 'this is:[^[:space:]] ' logfile); then
echo "value is: ${result#*:}"
fi
${varname#value}
расширяется до содержимого varname
, но с value
удалением с самого начала, если оно присутствует. Таким образом, ${result#*:}
удаляет все до первого двоеточия result
.
Однако это может не работать в системах без параметров, отличных от POSIX -o
, или -m
.
Если вы хотите поддерживать системы, отличные от GNU awk
, стоит ли рассмотреть этот инструмент: в отличие от ответов, требующих непереносимых расширений (например grep -P
), это должно работать на любой современной платформе (протестировано с GNU awk, недавними BSD awk и mawk; кроме того, никаких предупреждений с with gawk --posix --lint
):
# note that the constant 8 is the length of "this is:"
# GNU awk has cleaner syntax, but trying to be portable here.
if value=$(awk '
BEGIN { matched=0; } # by default, this will trigger END to exit as failure
/this is:/ {
match($0, /this is:([^[:space:]] )/);
print substr($0, RSTART 8, RLENGTH-8);
matched=1; # tell END block to use zero exit status
exit(0); # stop processing remaining file contents, jump to END
}
END { if(matched == 0) { exit(1); } }
'); then
echo "Found value of $value"
else
echo "Could not find $value in file"
fi
Ответ №4:
Вы можете искать все вплоть до, но не включая следующий пробел, подобный этому:
grep -Eo "this is:[^[:space:]] " logfile
[]
Вводит набор символов, которые вы ищете, а ^
в начале дополняет набор, поэтому набор символов, который вы ищете, является пробелом, но дополняется, т. Е. Не пробелом. В
нем говорится, что должен быть хотя бы один или несколько таких символов.
-E
Указывает grep
использовать расширенные регулярные выражения и -o
средства для печати только соответствующей части.
Комментарии:
1. Я бы предложил использовать
[^[:space:]]
, чтобы также остановиться на символах табуляции и c.2. @CharlesDuffy Да, это определенное улучшение — спасибо.