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