Удалить запись $ PATH на основе регулярного выражения

58
7

Я пытаюсь удалить запись в $ PATH, если эта запись содержит заданную строку foo. Например, PATH=/home/me/bin: /home/foo/bin: /usr/foo/bin: /bin станет PATH=/home/me/bin: /bin. Я в настоящее время

echo $PATH | perl -pe 's/:(.*?)foo(.*?):/:/g'

но это, кажется, удаление слишком большого количества записей, хотя я пытаюсь использовать не-жадные соответствия. Что я делаю не так?

спросил(а) 2014-06-05T13:06:00+04:00 6 лет, 4 месяца назад
1
Решение
81

Я начал создавать регулярное выражение, которое будет иметь дело со всеми комбинациями двоеточия с обоих концов, но оно быстро стало сложным. Но поскольку вы используете Perl (хороший выбор BTW), как о чем-то вроде:

perl -e 'print join(":", grep { $_ !~ m/foo/ } split( ":", '"$PATH"' ) );'

ответил(а) 2014-06-05T14:12:00+04:00 6 лет, 4 месяца назад
99

Я бы разделил строку, выделил допустимые части и снова присоединил строку:


perl -e 'print join ":", grep !/foo/, split ":", $ENV{PATH}'

ответил(а) 2014-06-05T14:05:00+04:00 6 лет, 4 месяца назад
58

Вы также можете использовать awk для прокрутки путей, распечатывая только те, которые не содержат foo:

awk -F: '{for (i=1; i<=NF; i++) if ($i !~ /foo/) {printf "%s%s", $i, (i==NF? RS : FS)}}'

объяснение

    -F: устанавливает : как разделитель полей. for (i=1; i<=NF; i++) петля через поля. if ($i !~/foo/) если путь не содержит строку foo, затем выполните следующее действие: printf "%s%s", $i, (i==NF? RS: FS) печатать строку, заканчивающуюся новой строкой или : зависимости от позиции. Если это последнее поле, новая строка; в противном случае :

Контрольная работа

$ cat a
/home/me/bin:/home/foo/bin:/usr/foo/bin:/bin
/home/me/bin:/home/fio/bin:/usr/foo/bin:/bin

$ awk -F: '{for (i=1; i<=NF; i++) if ($i !~ /foo/) {printf "%s%s", $i, (i==NF? RS : FS)}}' a
/home/me/bin:/bin
/home/me/bin:/home/fio/bin:/bin

ответил(а) 2014-06-05T13:10:00+04:00 6 лет, 4 месяца назад
57

Вы можете использовать:

perl -pe 's/:(.*?)foo[^:]*(?=:|$)//g' <<< "$PATH"
/home/me/bin:/bin

ответил(а) 2014-06-05T13:10:00+04:00 6 лет, 4 месяца назад
41

Хорошо, что вы используете неживое соответствие .*? в нижнем регулярном выражении.

echo $PATH | perl -pe 's/:(.*?)foo(.*?):/:/g'

Однако в вашем регулярном выражении есть недостаток, потому что вы не ограничивали допустимые символы, и поэтому он может захватывать ваши границы двоеточия.

Одна из причин, почему split - хороший инструмент. Он не только обеспечивает соблюдение границ, но и принятых символов между ними.

Конечно, это можно сделать с помощью регулярного выражения, как вы и предполагали:

echo $PATH | perl -pe 's/[^:=]*foo[^:]*:?//g'

Вышеупомянутое будет содержать трейлинг-двоеточие, если это последняя запись.

ответил(а) 2014-06-12T03:53:00+04:00 6 лет, 4 месяца назад
Ваш ответ
Введите минимум 50 символов
Чтобы , пожалуйста,
Выберите тему жалобы:

Другая проблема