Я изучаю Linux, и у меня есть проблема, которую мне, кажется, не удается решить самостоятельно.Вот:
grep строка из файла, который содержит 4 числа подряд, но не больше чем 4.
Я не уверен, как приблизиться к этому. Я могу искать определенные числа, но не их сумму в строке.
Существует два способа интерпретировать этот вопрос; я обращусь к обоим случаям. Вы могли бы хотеть к строкам дисплея:
Например, (1) отобразился бы 1234a56789
, но (2) не был бы.
Если Вы хотите отобразить все строки, которые содержат последовательность четырех цифр, которая является самостоятельно не частью любой более длинной последовательности цифр, один путь:
grep -P '(?<!\d)\d{4}(?!\d)' file
Это использует регулярные выражения Perl, который Ubuntu grep
(GNU grep), поддерживает через -P
. Это не будет соответствовать тексту как 12345
, и при этом это не будет соответствовать 1234
или 2345
это - часть его. Но это будет соответствовать 1234
в 1234a56789
.
В регулярных выражениях Perl:
\d
средства любая цифра (это - короткий способ сказать [0-9]
или [[:digit:]]
).x{4}
соответствия x
4 раза. ({
}
синтаксис не характерен для регулярных выражений Perl; это находится в расширенных регулярных выражениях через grep -E
также.) Так \d{4}
совпадает с \d\d\d\d
.(?<!\d)
отрицательная нулевая ширина, оглядываются утверждение. Это означает, "если не предшествуется \d
."(?!\d)
нулевая ширина отрицательное предварительное утверждение. Это означает, "если не сопровождается \d
."(?<!\d)
и (?!\d)
не соответствуйте тексту вне последовательности четырех цифр; вместо этого, они будут (при использовании вместе) предотвращают последовательность четырех цифр от себя являющийся согласованным, если это - часть более длинной последовательности цифр.
Используя просто оглядывание или просто предвидение недостаточно, потому что самая правая или крайняя левая четырехразрядная подпоследовательность была бы все еще подобрана.
Одно преимущество использования оглядывается, и предварительные утверждения то, что Ваш шаблон соответствует только самим четырехразрядным последовательностям а не сопроводительному тексту. Это полезно при использовании выделения цвета (с --color
опция).
ek@Io:~$ grep -P '(?<!\d)\d{4}(?!\d)' <<< 12345abc789d0123e4
12345abc789d0123e4
По умолчанию в Ubuntu, каждый пользователь имеет alias grep='grep --color=auto'
в их ~.bashrc
файл. Таким образом, Вы получаете цвет, выделяющийся автоматически при выполнении простой команды, запускающейся с grep
(это - когда псевдонимы расширены), и стандартный вывод является терминалом (это что --color=auto
проверки на). Соответствия обычно выделяются в оттенке красного цвета (близко к вермильону), но я показал его в полужирном курсивном. Вот снимок экрана:
И можно даже сделать grep
распечатайте только совпавший текст а не целую строку, с -o
:
ek@Io:~$ grep -oP '(?<!\d)\d{4}(?!\d)' <<< 12345abc789d0123e4
0123
Однако, если Вы:
grep
не поддерживает -P
или иначе не хочу использовать регулярное выражение Perl, и... затем можно достигнуть этого с расширенным регулярным выражением вместо этого:
grep -E '(^|[^0-9])[0-9]{4}($|[^0-9])' file
Это соответствует четырем цифрам и символу нецифры - или начало или конец строки - окружение их. Конкретно:
[0-9]
соответствия любая цифра (как [[:digit:]]
, или \d
в регулярных выражениях Perl) и {4}
означает "четыре раза". Так [0-9]{4}
соответствует четырехразрядной последовательности.[^0-9]
символы соответствий не в диапазоне 0
через 9
. Это эквивалентно [^[:digit:]]
(или \D
, в регулярных выражениях Perl).^
, когда это не появляется в [
]
скобки, соответствует началу строки. Точно так же $
соответствует концу строки.|
средства или и круглые скобки для группировки (как в алгебре). Так (^|[^0-9])
соответствует началу строки или символа нецифры, в то время как ($|[^0-9])
соответствует концу строки или символа нецифры.Таким образом, соответствия происходят только в строках, содержащих четырехразрядную последовательность ([0-9]{4}
) это одновременно:
(^|[^0-9])
), и($|[^0-9])
).Если с другой стороны, Вы хотите отобразить все строки, которые содержат четырехразрядную последовательность, но не содержат последовательности больше чем четырех цифр (даже тот, который является отдельным от другой последовательности только четырех цифр), то концептуально Ваша цель состоит в том, чтобы найти строки, которые соответствуют одному шаблону, но не другому.
Поэтому, даже если Вы знаете, как сделать это с единственным шаблоном, я предложил бы использовать что-то как второе предложение matt, grep
луг для этих двух шаблонов отдельно.
Вы сильно не извлекаете выгоду ни из одной из расширенных функций регулярных выражений Perl при выполнении этого, таким образом, Вы могли бы предпочесть не использовать их. Но в соответствии с вышеупомянутым стилем, вот сокращение использования решения matt \d
(и фигурные скобки) вместо [0-9]
:
grep -P '\d{4}' file | grep -Pv '\d{5}'
Так как это использует [0-9]
, путь matt является более портативным - он будет работать над системами где grep
не поддерживает регулярные выражения Perl. Если Вы используете [0-9]
(или [[:digit:]]
) вместо \d
, но продолжите использовать {
}
, Вы получаете мобильность пути matt немного более кратко:
grep -E '[0-9]{4}' file | grep -Ev '[0-9]{5}'
Если Вы действительно предпочитаете a grep
управляйте этим
grep
s разделенный каналом, как выше)... затем можно использовать:
grep -Px '(\d{0,4}\D)*\d{4}(\D\d{0,4})*' file
-x
флаг делает grep
отобразите только строки, где вся строка соответствует (а не любая строка, содержащая соответствие).
Я использовал регулярное выражение Perl, потому что я думаю краткость \d
и \D
существенно увеличьте ясность в этом случае. Но если Вам нужно что-то портативное к системам где grep
не поддерживает -P
, можно заменить их [0-9]
и [^0-9]
(или с [[:digit:]]
и [^[:digit]]
):
grep -Ex '([0-9]{0,4}[^0-9])*[0-9]{4}([^0-9][0-9]{0,4})*' file
Путем эти регулярные выражения работа:
В середине, \d{4}
или [0-9]{4}
соответствия одна последовательность четырех цифр. У нас может быть больше чем один из них, но у нас должен быть по крайней мере один.
Слева, (\d{0,4}\D)*
или ([0-9]{0,4}[^0-9])*
нуль соответствий или больше (*
) экземпляры не больше чем четырех цифр сопровождаются нецифрой. Нулевые цифры (т.е. ничто) являются одной возможностью для "не больше чем четырех цифр". Это соответствует (a) пустой строке или (b) любой строке, заканчивающейся в нецифре и не содержащей любые последовательности больше чем четырех цифр.
Начиная с текста сразу слева от центрального \d{4}
(или [0-9]{4}
) должно или быть пустым или закончиться нецифрой, это предотвращает центральное \d{4}
от соответствия четырем цифрам, которые имеют другую (пятую) цифру только слева от них.
Справа, (\D\d{0,4})*
или ([^0-9][0-9]{0,4})*
нуль соответствий или больше (*
) экземпляры нецифры, сопровождаемой не больше чем четырьмя цифрами (которым, как прежде, мог быть четыре, три, два, один, или даже ни один вообще). Это соответствует (a) пустой строке или (b) любой строке, начинающейся в нецифре и не содержащей любые последовательности больше чем четырех цифр.
Начиная с текста сразу направо от центрального \d{4}
(или [0-9]{4}
) должно или быть пустым или запуститься с нецифры, это предотвращает центральное \d{4}
от соответствия четырем цифрам, которые имеют другую (пятую) цифру только направо от них.
Это гарантирует, что четырехразрядная последовательность присутствует где-нибудь, и что никакая последовательность пяти или больше цифр не присутствует нигде.
Это не плохо или неправильно сделать это этот путь. Но возможно самая важная причина рассмотреть эту альтернативу состоит в том, что она разъясняет преимущество использования grep -P '\d{4}' file | grep -Pv '\d{5}'
(или подобный) вместо этого, как предложено выше и в ответе matt.
С тем путем ясно, что Ваша цель состоит в том, чтобы выбрать строки, которые содержат одну вещь, но не другого. Плюс синтаксис более просто (таким образом, он может быть более быстро понят под многими читателями/специалистами по обслуживанию).
Это покажет Вам 4 числа подряд, но не больше
grep '[0-9][0-9][0-9][0-9][^0-9]' file
Примечание, которое ^ означает не
существует проблема с этим, хотя я не уверен, как зафиксировать..., если число является концом строки тогда это, привычка обнаруживается.
Эта более ужасная версия однако работала бы на тот случай
grep '[0-9][0-9][0-9][0-9]' file | grep -v [0-9][0-9][0-9][0-9][0-9]
Если grep
не поддерживает регулярные выражения perl (-P
), используйте следующую команду оболочки:
grep -w "$(printf '[0-9]%.0s' {1..4})" file
где printf '[0-9]%.0s' {1..4}
выдаст 4 раза [0-9]
. Этот метод полезен, когда у вас есть длинные цифры, и вы не хотите повторять шаблон (просто замените 4
на количество цифр, которое вы ищете).
Использование -w
будет искать все слова. Однако, если вас интересуют буквенно-цифровые строки, такие как 1234a
, то добавьте [^0-9]
в конце шаблона, например,
grep "$(printf '[0-9]%.0s' {1..4})[^0-9]" file
Использование $()
в основном является заменой команды . Проверьте этот пост , чтобы увидеть, как printf
повторяет паттерн.
Можно попробовать ниже команды путем замены файла фактическое имя файла в системе, которую можно также проверить это учебное руководство на большее количество использования команды grep:
grep-E' (^ | [^0-9]) [0-9] {4} ($ | [^0-9])' файл