Home > OS >  shell scripting process substitution <() inside command substitution $()
shell scripting process substitution <() inside command substitution $()

Time:09-21

I have a command with an output of 1 that is something like:

cmp -bl <(cmp -bl <(echo ABCDEF) <(echo ABDCEF)| wc -l) <(echo 0) |wc -l

I need to compare the command output with a value inside an if statement:

if [ $(cmp -bl <(cmp -bl <(echo ABCDEF) <(echo ABDCEF)| wc -l) <(echo 0) |wc -l) = "1" ]; then ...

There error that I have is syntax related: syntax error near unexpected token ('

CodePudding user response:

Just leave a space after [ and before ]. [ is an actual command similar to test. You need to separate the command from its parameters. ] is not a command but syntax rules for parameters of [ command requires it to be separated as well.

if [ $(cmp -bl <(cmp -bl <(echo ABCDEF) <(echo ABDCEF)| wc -l) <(echo 0) |wc -l) = "1" ]; then ...

CodePudding user response:

This seems very convoluted to me. For example the usage of cmp foo <(echo 0) to compare the content of foo (foo itself being the result of a wc -l on a cmp) to 0. But I surmise that you already understand that, that you understand that this is a Rube-Goldberg contraption instead of "== 0", and you understand that each <() fork a process, and return a name of pipes from this process (it has to be used when you need to pass a filename containing the result of an execution to command).

If not, you should explain what you are really trying to do, because, even replacing the <(echo ...) by real commands (I also surmise those are just examples), there is no way those several stages of cmp and wc are the correct way.

That being said, just add a space around [ and ], and it will do exactly what you intended. (edit: as already said by others in faster reply and comments. I type too long answers... I do not delete this answer, because the preamble may be relevant)

EDIT: to reply more on the usage part

  • No need, as seen in comments, for two layers of wc -l (one is already a strange way, but if it works...)
  • Be careful of how you compare things.
    • Mine (in comments), using == works only in linux, because wc output is a string of digits, with nothing more. It doesn't on mac, because of heading spaces. So 1 is not the same as 1.
    • Yours, is the same. But since you used [ instead of [[, [ being and external command, while [[ is bash syntax ([[ is better: no fork of a process), the spaces of 1 are lost during the passing of the argument to [ command
    • the cleanest solution is probably to use -eq which compares the integers, regardless of how they are printed.

So, altogether

if [[ $(cmp -bl <(echo string1) <(echo string2) | wc -l) -eq 1 ]]
then
   echo one and only one difference
fi

should work. Again, not sure it is the fastest, nor the shortest, nor the most elegant solution. But as long as nobody provides a better one...

  • Related