Лучший способ сделать «эхо $ х | sed… »и« echo $ x | grep… ”


14

Я часто нахожу это в сценариях (и, должен признать, сам это пишу):

a=$(echo "$x" | sed "s/foo/bar/")

или

if echo "$x" | grep -q foo
then
    ...
fi

Рассмотрим "foo", чтобы включить некоторые регулярные выражения.

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

Я просто не могу найти это. Кто-нибудь?


Я ожидаю, что это выражение часто используется из-за сочетания невежества (не зная альтернатив) и ремонтопригодности (зная альтернативы, но выбирая это как более простое для понимания). Я могу сразу сказать, что делают ваши примеры, но мне нужна ссылка на оболочку, чтобы выяснить альтернативы в ответах Гравити и Дэна МакГа.
Квик-кихот

3
Между прочим, предпочтительный метод выполнения подстановки команд - с помощью $()обратных кавычек.
Приостановлено до дальнейшего уведомления.

2
Это также хорошая идея заключать в кавычки расширения, чтобы пробел был защищен: a="$(echo "$x" | sed "s/foo/bar/")"и if echo "$x" | grep foo; ….
Крис Джонсен

Хорошие замечания о $ () против ``. Я вижу, что мои навыки в Bash еще не так велики.
DevSolar

Ответы:


12

Если вы не предполагаете конкретную оболочку, нет лучшего способа сделать это, чем «pipe echo to tool» (или просто сам «инструмент», такой как expr ); это все, на что вы действительно можете рассчитывать с традиционной оболочкой Bourne и / или оболочкой POSIX . Если вы рассматриваете другие оболочки, то есть некоторые другие встроенные возможности.

Кш имеет

  • дополнительные модели: ?(pattern-list), *(pattern-list), {n}(pattern-list), {n,m}(pattern-list), @(pattern-list), !(pattern-list);
  • %P Printf спецификатор , чтобы преобразовать расширенное регулярное выражение в образец (и %Rдля расширенного регулярного выражения к шаблону);
  • expr == patternусловие [[ expr ]]испытаний;
  • ${param/pattern/replacement}расширение параметра.

Баш имеет

  • extglobвариант для того, чтобы большинство дополнительных моделей KSH (нет {n}и {n,m});
  • expr == patternусловие (в [[ expr ]]тестах);
  • ${param/pattern/replacement}расширение параметра;
  • (в более новых версиях) expr =~ extregexpусловие (в [[ expr ]]тестах), которое может соответствовать расширенным регулярным выражениям
    • с заключенными в скобки подвыражениями и BASH_REMATCHпараметром можно было бы сделать замены в стиле sed .

зш имеет

  • свои собственные расширенные шаблоны с EXTENDED_GLOBопцией;
  • ksh -подобные расширенные шаблоны с KSH_GLOBопцией;
  • expr == patternусловие (в [[ expr ]]тестах);
  • ${pattern/pattern/replacement}расширение параметра;
  • expr =~ extregexpусловие (в [[ expr ]]тестах) , которые могут соответствовать против расширенных регулярных выражений,
    • он может использовать PCRE вместо простых расширенных регулярных выражений, если установлена ​​опция RE_MATCH_PCRE,
    • с заключенными в скобки подвыражениями, MATCHпараметром и matchпараметром (или BASH_REMATCHс установленным BASH_REMATCHпараметром) можно выполнить замены в стиле sed ;
  • zsh/pcreмодуль , который предлагает pcre_compile, pcre_studyи pcre_matchкоманда и -pcre-match тест выполняется условие (в [[ expr ]]тестах);
  • zsh/regexмодуль , который предлагает -regex-match тестовое условие (в [[ expr ]]тестах).

Вау. Столько, сколько можно пожелать. Определенно победитель.
DevSolar

6

Чтобы заменить строку sed, сделайте что-то вроде

${a/foo/bar} или ${a//foo/bar}

В первой форме заменяется только первый экземпляр. Вторая форма - это глобальный поиск и замена.

В вашем случае это было бы

Вместо того:

if echo $x | grep foo
then
    ...
fi

Рассмотрите возможность использования:

if [ $x =~ foo ]
then
    ...
fi

Где fooэто регулярное выражение.


В каких оболочках это работает?
Пельтье

1
if [ $x =~ foo ]выдает здесь сообщение об ошибке. if [[ $x =~ foo ]]Однако прекрасно работает. Благодарность!
DevSolar

1
Все это bashisms, они требуют bash. Кроме того, =~требуется bash> = 3 iirc.
ℝaphink

1
Кроме того, в этих примерах foo не является регулярным выражением (как в PCRE), а использует подстановочные знаки. Есть много хорошего в bash, в разделе «Расширение параметров». Я особенно ценю такие вещи, как ${a##foo}и ${a%%bar}.
ℝaphink

3
Оператор соответствия =~использует регулярные выражения. Это верно, например: [[ "abcdddde" =~ ^a.*d+.g* ]](это ноль или больше g, а не g-wildcard, например).
Приостановлено до дальнейшего уведомления.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.