5

On a Centos 6 machine, this works:

bash -c 'if grep -qP --line-buffered ".+" <(tail -n 1000 -F catalina.out) ; then echo "yes"; fi'

and this doesn't:

sh -c 'if grep -qP --line-buffered ".+" <(tail -n 1000 -F catalina.out) ; then echo "yes"; fi'

I get:

sh: -c: line 0: syntax error near unexpected token `('
sh: -c: line 0: `if grep -qP --line-buffered ".+" <(tail -n 1000 -F catalina.out) ; then echo "yes"; fi'

Nevermind the grep and tail. The problem is with the process substitution thingy: <(...)

Can someone tell me what sh does differently here?

[EDIT]

Thanks for the answers!

The problem arose while using capistrano for deployments. It defaults to using sh but I changed that to bash now. The reason I couldn't do the normal piping is that when using tail -F | grep -q --line-buffered, grep won't exit immediately after a match. There has to be one more edit to the file like echo "" >> catalina.out and this was not acceptable in my situation.

Leon
  • 31,443
  • 4
  • 72
  • 97
Cpt. Senkfuss
  • 1,347
  • 3
  • 12
  • 20
  • See also [Difference between `sh` and `bash`](https://stackoverflow.com/questions/5725296/difference-between-sh-and-bash) – tripleee Apr 12 '23 at 04:17

3 Answers3

6

The syntax <(...) is only supported by BASH.

For any POSIX shell, use this approach:

sh -c 'tail -n 1000 -F catalina.out | if grep -qP --line-buffered ".+" ; then ...'

i.e. move the stdin redirection in front of the if with a pipe. The if will pass stdin on to the grep.

if tail ...| grep won't work since the if won't be able to see it's then/fi because the pipe separates processes.

chepner
  • 497,756
  • 71
  • 530
  • 681
Aaron Digulla
  • 321,842
  • 108
  • 597
  • 820
  • `if tail ... | grep ... ; then ... fi` works for me in dash and bash in posix mode. – choroba Sep 05 '13 at 09:03
  • It works in ksh. `sh` on my systems is dash or bash in posix mode. – choroba Sep 06 '13 at 09:38
  • @choroba: Interesting. I'm pretty sure it didn't work in Solaris with Korn Shell. – Aaron Digulla Sep 06 '13 at 12:27
  • 1
    @AaronDigulla, eh? Using a pipeline in the conditional clause of an `if` statement is supported even in 1970s-era Bourne; I'm certain that every extant release of ksh would have supported it -- and ksh93 supports process substitution, so even the OP's original code would be good there. – Charles Duffy Oct 27 '16 at 16:13
6

You should note that process substitution (<(...)) isn't specified by POSIX. So if you were running bash in POSIX mode by invoking it with sh or saying:

set -o posix

then you'd observe errors!

From the bash manual:

Starting Bash with the --posix command-line option or executing ‘set -o posix’ while Bash is running will cause Bash to conform more closely to the POSIX standard by changing the behavior to match that specified by POSIX in areas where the Bash default differs.

...

Process substitution is not available.

chepner
  • 497,756
  • 71
  • 530
  • 681
devnull
  • 118,548
  • 33
  • 236
  • 227
4

Also take note that if Bash is invoked with the name sh, it tries to mimic the startup behavior of historical versions of sh as closely as possible, while conforming to the POSIX standard as well.

If your sh is actually a link to bash, then this is what's causing that.

Running sh --version; sh -c ': <(echo a)' should give you enough info.

konsolebox
  • 72,135
  • 12
  • 99
  • 105