diff command not working inside bash shell script - bash

I am trying to run
diff <(tar -tvf HIVE_CLIENT.tar.gz | sort) <(tar -tvf YARN_CLIENT.tar.gz | sort)
putting this command inside script, when I execute script it shows error
syntax error near unexpected token `(' "
But when I do not put inside script rather than run from shell directly it works.

Probably your script is run with /bin/sh and not with /bin/bash, but command substitution is a bash feature and not implemented in sh. So I suppose you are using bash as your shell which is why it is working from the command line.
Try adding this prefix to your script, and remove existing shebangs (like #!/bin/sh or similar):
#!/bin/bash

You should try following two actions:
Use #!/bin/bash as your shebang (First line of your script)
This may be needed based on your bash, use only if opetion 1 does not help. Use following commands to flip between posix mode which is needed for process substitution:
set +o posix
diff <(tar -tvf HIVE_CLIENT.tar.gz | sort) <(tar -tvf YARN_CLIENT.tar.gz | sort)
set -o posix
Example:
wc -l <(ls -lrt)
sh: syntax error near unexpected token `('
set +o posix
wc -l <(ls -lrt)
114 /dev/fd/00
set -o posix
wc -l <(ls -lrt)
sh: syntax error near unexpected token `('

Related

Inline unix command as filename [duplicate]

This question already has answers here:
Why does my Bash code fail when I run it with 'sh'?
(2 answers)
Closed 4 years ago.
I have the following bash script test.sh (with execution permissions):
#!/bin/sh
CAT_BIN="cat"
"$CAT_BIN" <(tail -n +2 test.sh)
It gives me that error when I run it:
$ ./test.sh
./test.sh: line 4: syntax error near unexpected token `('
./test.sh: line 4: `"$CAT_BIN" <(tail -n +2 test.sh)'
However, when I source the following commands it executes alright.
$ CAT_BIN="cat"
$ "$CAT_BIN" <(tail -n +2 test.sh)
How can this work in a script? (Use <(tail -n +2 test.sh) inline as a filename argument)
The <(tail -n +2 test.sh) construct is a bash feature, so you need to run your script in the bash shell,
Replace your top line
#!/bin/sh
with
#!/bin/bash
(Or the proper path to the bash executable if it is not /bin/bash on your system)
Note, even if /bin/sh is e.g. a symlink to bash, it will start bash in posix compatibility mode when you run it as /bin/sh , and many bash specific features will not be available)

Bash functions inside process substitution

Getting an error trying to call a function inside a process substitution.
Is there any way to do this?
#!/bin/bash
function testfunc
{
echo "bork"
}
diff <(testfunc) <(echo "bork")
The error is:
bork.sh: line 7: syntax error near unexpected token `('
bork.sh: line 7: `diff <(testfunc) <(echo "bork")'
--Update--
Problem was calling sh bork.sh, instead of bash ./bork.sh . Moral of the story make sure which shell you are executing with.
There's no problem here:
$ chmod +x test.sh
$ ./test.sh
Clear diff. No problem!
$ bash -x ./test.sh
+ diff /dev/fd/63 /dev/fd/62
++ testfunc
++ echo bork
++ echo bork
Proof that it worked
Troubleshooting:
Maybe you
run in a restricted shell
you don't have /dev/fd available/mounted correctly (due to somekind of secure chroot jail?)
The problem is probably that you're running the command with sh instead of bash.
$ cat > xx.sh
#!/bin/bash
function testfunc
{
echo "bork"
}
diff <(testfunc) <(echo "bork")
$ sh xx.sh
xx.sh: line 7: syntax error near unexpected token `('
xx.sh: line 7: `diff <(testfunc) <(echo "bork")'
$ bash xx.sh
$
The process substitution is not portable to the shell in /bin/sh. See the Bash manual on POSIX mode and bullet 28:
Process substitution is not available.
Tested on Mac OS X 10.10.5 (Yosemite).

Using bash -c and Globbing

I'm running gnu-parallel on a command that works fine when run from a bash shell but returns an error when parallel executes it with bash using the -c flag. I assume this has to do with the special globbing expression I'm using.
ls !(*site*).mol2
This returns successfully.
With the flag enabled the command fails
/bin/bash -c 'ls !(*site*).mol2'
/bin/bash: -c: line 0: syntax error near unexpected token `('
The manual only specifies that -c calls for bash to read the arguments for a string, am I missing something?
Edit:
I should add I need this to run from a gnu-parallel string, so the end resultant command must be runnable by /bin/bash -c "Some Command"
You should try the following code :
bash <<EOF
shopt -s extglob
ls !(*site*).mol2
EOF
Explanation :
when you run bash -c, you create a subshell, and shopt settings are not inherited.
EDIT
If you really need a one liner :
bash -O extglob -c 'ls !(*site*).mol2'
See this thread

Makefile - "$" not taken into account for shell command

I have a Makefle with the following rule
bash -c "find . |grep -E '\.c$|\.h$|\.cpp$|\.hpp$|Makefile' | xargs cat | wc -l"
I'm expecting make to run the quoted bash script and to return the number of line in my project.
Running directly the command in a terminal does the work, but it doesn't work in makefile.
If I remove $ from the script, it does work ... but not as expected (since I only want *.{c,cpp,h,hpp,Makefile}.
Why bash -c doesn't run correctly my script?
if you write the rule like the following, it should produce the result you want:
target:
#echo $(shell find . | grep -E '\.c$$|\.h$$|\.cpp$$|\.hpp$$|Makefile' | xargs cat | wc -l)
In Makefiles, $ is used for make variables such as $(HEADERS), where HEADERS would have been defined previously using =.
To use a $ in inline bash, you have to double them to escape them. $$VAR will refer to a shell variable, and .c$$ and so on should escape the $ for the regex you're working with.
The following should suffice in escaping the $'s for what you're trying to accomplish
bash -c "find . |grep -E '\.c$$|\.h$$|\.cpp$$|\.hpp$$|Makefile' | xargs cat | wc -l"
Additionally, you can use bash globally in your Makefile as opposed to the default /bin/sh if you add this declaration:
SHELL = /bin/bash
With the above, you should be able to use the find command without needing the bash -c and quotes. The following should work if SHELL is defined as above:
find . |grep -E '\.c$$|\.h$$|\.cpp$$|\.hpp$$|Makefile' | xargs cat | wc -l
Also, note that you can, and will often see SubShells used for this purpose. These are created with (). This will make any variables defined by the inner shell local to that shell and its group of commands.

Code does not work with sh -c, but works on sh directly

$ sh
sh-3.2$ if
> ps -ef | grep apple ;
> then
> echo APPLE
> fi ;
lazer 7584 7571 0 04:36 pts/4 00:00:00 grep apple
APPLE
sh-3.2$ exit
exit
$ which sh
/bin/sh
$ /bin/sh -c if ps -ef | grep apple ; then echo APPLE fi ;
bash: syntax error near unexpected token `then'
$
As above, my simple if statement works as expected when executed line by line but gives me the following error when executed using sh -c:
bash: syntax error near unexpected token `then'
What am I missing here?
Your interactive shell will be escaping the invocation via sh -c. In particular it's taking everyting after the semi-colon as a new statement.
Quote everything that you're feeding to /bin/sh e.g.
$ /bin/sh -c "if ps -ef | grep apple ; then echo APPLE fi ;"
I think you may also need to delimit further using semi-colons given that you're condensing everything onto one line, and would perhaps suggest you could use a heredoc.

Resources