Тут є дві проблеми: як @AFH вказував, \sце стенограма Perl, а не частина стандартного синтаксису POSIX. Стандартний спосіб представити це з класом символів [[:space:]]. Друга проблема полягає в тому, що змінні посилання не розширюються всередині одиничних лапок; вам потрібно використовувати подвійні лапки (і уникати тієї $частини регулярного вираження).
Крім того, декілька стилістичних рекомендацій: $( )як правило, перевагу над задніми посиланнями для заміни команд (це легше читати, і не має деяких дивних незвичних синтаксичних дивацтв, які мають backticks). Але в цьому випадку ви можете пропустити розширення команди; замість того, щоб використовувати wc -lі порівнювати з нулем, щоб побачити, чи були відповідність, просто використовуйте grepстатус виходу в якості тесту (і -qможливість уберегти його від друку відповідності). Також не забудьте подвоїти посилання на змінні (наприклад, у echoкоманді).
Ось мій рекомендований перепис:
if dpkg -l | grep -Eq "(^|[[:space:]])$i(\$|[[:space:]])"; then echo "$i"; fi
EDIT: як зазначав igor у коментарі, це не працюватиме з іменами пакетів, які містять метасимволи regex (наприклад, g ++ - 5). Можна заздалегідь обробити ім'я пакета, щоб уникнути метахарактерів, але це досить брудно. Але є більш простий спосіб: якщо ви використовуєте bash (а не якусь іншу оболонку), ви можете скористатись базовою функцією rehex bash, щоб виконати відповідність безпосередньо:
if [[ "$(dpkg -l)" =~ (^|[[:space:]])"$i"(\$|[[:space:]]) ]]; then echo "$i"; fi
Причина цього працює в тому, що $iв середині шаблону є подвійні лапки, що вказує bash відповідати йому як буквальному рядку (тобто ігнорувати будь-які метагерактеристики регулярних виразів у ньому).
g++-5абоg++-4.9. Якісь ідеї?