Better way to do "echo $x | sed ..." and "echo $x | grep ..."

Unless you assume a specific shell, there is no better way to do this than “pipe echo to tool” (or just a “tool” itself like expr); it is all you can really count on with the traditional Bourne shell and/or the POSIX shell. If you consider other shells, then there are some other built-in possibilities.

ksh has

  • extra patterns: ?(pattern-list), *(pattern-list), {n}(pattern-list), {n,m}(pattern-list), @(pattern-list), !(pattern-list);
  • the %P printf specifier to convert a extended regular expression into a pattern (and %R for extended regular expression to pattern);
  • the expr == pattern condition in [[ expr ]] tests;
  • the ${param/pattern/replacement} parameter expansion.

bash has

  • the extglob option to enable most of the extra patterns of ksh (no {n} and {n,m});
  • the expr == pattern condition (in [[ expr ]] tests);
  • the ${param/pattern/replacement} parameter expansion;
  • (in newer versions) the expr =~ extregexp condition (in [[ expr ]] tests) that can match against extended regular expressions
    • with parenthesized subexpressions and the BASH_REMATCH parameter, sed-style replacements could be done.

zsh has

  • its own extended patterns with the EXTENDED_GLOB option;
  • ksh-like extended patterns with the KSH_GLOB option;
  • the expr == pattern condition (in [[ expr ]] tests);
  • the ${pattern/pattern/replacement} parameter expansion;
  • the expr =~ extregexp condition (in [[ expr ]] tests) that can match against extended regular expressions,
    • it can use PCRE instead of plain extended regular expressions if the RE_MATCH_PCRE option is set,
    • with parenthesized subexpressions, the MATCH parameter, and the match parameter (or BASH_REMATCH with the BASH_REMATCH option set), sed-style replacements could be done;
  • the zsh/pcre module that offers pcre_compile, pcre_study, and pcre_match commands and the -pcre-match test condition (in [[ expr ]] tests);
  • the zsh/regex module that offers the -regex-match test condition (in [[ expr ]] tests).

To replace the sed line, do something like

${a/foo/bar} or ${a//foo/bar}

In the first form, only the first instance is replaced. The second form is a global search & replace.

In your case, it would be

Instead of:

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

Consider using:

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

Where foo is a regular expression.


A good posix compatible way for testing if a variable contains a pattern is:

test ${var##*foo*} || <do something>;

The syntax of the parameter expansion is:

 ${parameter##pattern}

where pattern is a shell pattern.