Вопрос или проблема
Я учился использовать команды linux, когда заметил это странное необычное поведение команды “grep”. В каталоге /usr/bin
, когда я выполняю:
me@me-desktop:/usr/bin$ ls -l | grep bashb*
-rwxr-xr-x 1 root root 6988 31 мар 2024 bashbug
что и ожидалось, но если я сделаю то же самое вне /usr/bin
me@me-desktop:~/Code/linux$ ls -l /usr/bin | grep bashb*
-rwxr-xr-x 1 root root 1446024 31 мар 2024 bash
-rwxr-xr-x 1 root root 6988 31 мар 2024 bashbug
-rwxr-xr-x 1 root root 4527 17 апр 2023 dh_bash-completion
lrwxrwxrwx 1 root root 4 20 авг 23:14 rbash -> bash
Как видите, теперь он необязателен игнорирует последнюю b
в bashb
.
Это происходит и в многих других случаях. Например, если вы выполняете apt list | grep lib*
, то он также выводит те, которые содержат li
.
Ответ или решение
Странное поведение команды grep с ls и регулярными выражениями
При использовании командной строки в Linux, особенно таких, как ls
и grep
, могут возникнуть неожиданные результаты, которые могут сбивать с толку. Рассмотрим случай, когда вы заметили странное поведение команды grep
, проверяя имена файлов в директории /usr/bin
.
Описание проблемы
Вы выполнили следующую команду в директории /usr/bin
:
me@me-desktop:/usr/bin$ ls -l | grep bashb*
В результате вы получили:
-rwxr-xr-x 1 root root 6988 Mar 31 2024 bashbug
Это соответствует вашим ожиданиям, так как bashbug
содержит bashb
.
Однако, когда вы выполнили ту же команду в другой директории, как показано ниже:
me@me-desktop:~/Code/linux$ ls -l /usr/bin | grep bashb*
Вы получили больше результатов:
-rwxr-xr-x 1 root root 1446024 Mar 31 2024 bash
-rwxr-xr-x 1 root root 6988 Mar 31 2024 bashbug
-rwxr-xr-x 1 root root 4527 Apr 17 2023 dh_bash-completion
lrwxrwxrwx 1 root root 4 Aug 20 23:14 rbash -> bash
Причины странного поведения
Причина такого поведения заключается в том, как работает globbing (маскировка имен файлов) в оболочке Bash, а также в том, как grep
обрабатывает регулярные выражения.
-
Глоббинг в Bash:
Когда вы пишетеbashb*
, оболочка интерпретирует*
как подстановочный символ. Это значит, что Bash сначала пытается подставить все файлы и директории, соответствующие шаблонуbashb*
. В контексте первой команды (ls -l
) в директории/usr/bin
, подстановка ничего не возвращает, так как нет файлов, соответствующих шаблону передgrep
. Таким образом,grep
получает чистый шаблонbashb
без дополнительных символов после него. -
Обработка регулярных выражений в grep:
Когда вы выполняетеgrep bashb*
в втором случае,grep
получает список, где шаблон включает самые разные строки, и это оказывается не таким уж строгим. Pitfall заключается в том, что*
в регулярных выражениях, как правило, интерпретируется как "ноль или более вхождений предыдущего символа". То естьbashb*
может соответствоватьbash
,bashb
, и даже строкам, которые содержатbash
, а затем некоторый символ (или не содержат его). Поэтому результат содержит какbash
, так иbashbug
. -
Другие примеры:
Подобное поведение наблюдается и в других ситуациях. Например:apt list | grep lib*
Данная команда возвращает результаты не только с
lib
, но и сli
, так как*
работает аналогичным образом, расширяя шаблон.
Рекомендации
-
Экранирование специального символа:
Если вы хотите, чтобыgrep
обрабатывал именно то, что вы указали без глобального расширения, вы можете экранировать*
с помощью обратного слэша:ls -l | grep 'bashb\*'
Или использовать одинарные кавычки для определения строки:
ls -l | grep 'bashb*'
-
Использование регулярных выражений:
Если вам нужно точное совпадение, используйте метасимвол^
в начале и$
в конце:ls -l | grep '^bashb$'
Это гарантирует, что
grep
будет искать точное совпадение с ‘bashb’, а не с любыми строками, которые могут его содержать.
Заключение
В процессе работы с Linux-командами важно понимать, как работает оболочка и инструменты с регулярными выражениями. Это знание поможет избежать путаницы и повысит эффективность работы с командной строкой. При возникновении сомнений в поведении команды всегда обращайтесь к документации и пробуйте различные варианты команд для достижения нужного результата.