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

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

Например,

dpkg -l | grep -w "rpm"

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

Я нашел решение для этого с помощью регулярных выражений. Проблема в том, что он не работает в скрипте 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 .

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

2 ответа2

1

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

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

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

Руководство grep говорит, что -P экспериментальный, но он работает для меня на Ubuntu 16.04.

1

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

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

Вот мой рекомендуемый переписать:

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

РЕДАКТИРОВАТЬ: как указал игорь в комментарии, это не будет работать с именами пакетов, которые содержат метасимволы регулярных выражений (например, g++- 5). Возможно предварительно обработать имя пакета, чтобы избежать метасимволов, но это довольно грязно. Но есть более простой способ: если вы используете bash (а не какую-либо другую оболочку), вы можете использовать встроенную возможность регулярного выражения bash для непосредственного сопоставления:

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

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

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .