Экранирование символов для точного условия grep в сценарии Bash

у меня есть базовый скрипт для поиска конкретных установленных пакетов в Linux. Если не найден -> распечатать пакет.

Я grep -w, но он не работает должным образом с - символ.

например,

dpkg -l | grep -w "rpm"

также найдете rpm-common.

я нашел решение для этого с помощью regex. Проблема это не работает в bash-скрипт.

устранение:

dpkg -l | grep -E '(^|s)string($|s)'

состояние:

if [ `dpkg -l | grep -E '(^|s)$i($|s)' | wc -l` = 0 ]; then echo$i; fi

$i ссылается на значение массива, например arr[index]=$i.

какие экранирующие символы мне нужно использовать, чтобы условие работало?

1
задан Peter Mortensen
21.01.2023 9:29 Количество просмотров материала 2547
Распечатать страницу

2 ответа

здесь есть две проблемы: как указал @AFH,\s является сокращением Perl, а не частью стандартного синтаксиса POSIX. Стандартный способ представить это-класс символов [[:space:]]. Вторая проблема заключается в том, что ссылки на переменные не раскрываются внутри одинарных кавычек; вам нужно использовать двойные кавычки (и экранировать $ это часть регулярного выражения).

кроме того, несколько стилистических рекомендаций: $( ) обычно предпочтительнее, чем backticks для команды substitution (его легче читать и у него нет некоторых странных странностей синтаксиса, которые есть у обратных ссылок). Но в этом случае можно пропустить расширение команды; вместо использования wc -l и по сравнению с нулем, чтобы увидеть, если были какие-либо матчи, просто используйте grepс выездом статус теста (и -q опция, чтобы держать его от печати матча). Кроме того, убедитесь, что ссылки на переменные заключены в двойные кавычки (например, в echo command).

вот мои рекомендации перепишите:

if dpkg -l | grep -Eq "(^|[[:space:]])$i($|[[:space:]])"; then echo "$i"; fi

EDIT: как отметил Игорь в комментарии, это не будет работать с именами пакетов, которые содержат метасимволы регулярных выражений (например, g++-5). Можно предварительно обработать имя пакета, чтобы избежать метасимволов, но это довольно грязно. Но есть более простой способ: если вы используете bash (а не какую-то другую оболочку), вы можете использовать родную возможность регулярного выражения bash для прямого сопоставления:

if [[ "$(dpkg -l)" =~ (^|[[:space:]])"$i"($|[[:space:]]) ]]; then echo "$i"; fi

причина, по которой это работает, заключается в том, что $i в середине шаблон находится в двойных кавычках, что говорит bash, чтобы соответствовать ему как литеральной строке (т. е. игнорировать любые метасимволы регулярных выражений в нем).

1
отвечен Gordon Davisson 2023-01-22 17:17

расширенные регулярные выражения не поддерживают \s, но Perl REs делает, поэтому попробуйте использовать -P вместо -E:

dpkg -l | grep -P '(^|\s)rpm($|\s)'

See этой ссылке для получения дополнительной информации.

на grep инструкции сказано, что -P экспериментальная, но это работает для меня на Ubuntu 16.04.

1
отвечен AFH 2023-01-22 19:34

Постоянная ссылка на данную страницу: [ Скопировать ссылку | Сгенерировать QR-код ]

Ваш ответ

Опубликуйте как Гость или авторизуйтесь

Имя
Вверх