Здесь есть две проблемы: как указал @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, чтобы оно соответствовало буквальной строке (т.е. игнорировало любые метасимволы регулярных выражений в нем).