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