This is slightly off topic, but something I stumbled upon quite recently. I'm sure veteran unix programmers would have encountered this too.
I'll start off with something almost everyone knows - not all
greps are equal. Not all
cuts are the same. There might be certain options available to binaries in one flavor that are not available to their equivalent binaries in a different flavor. For example,
cut --complement is available in GNU
cut, but not in macOS default BSD's
Yesterday, I discovered that shell are by themselves quite different too. It seems totally obvious right now, but when I encountered the bug, it puzzled me.
I was testing a shell script
x.sh that has a statement:
python util.py -a <(cut -f2 input1.txt) -b input2.txt
Now, this uses Process Substitution (
<(...)) - a construct I use very often. I've tested it on an interactive shell, I've used it in shell scripts, so I know it works.
Except, this time it didn't. Took me a while to zero in on this statement, but when I did, it shocked me. How does something so basic not work?
When I started learning Linux in 2005, I was told I could use the dot-slash (
./) or the
sh binary to execute a shell script. Turns out, I was using the syntax
sh x.sh to execute the script, out of force of habit. And even though I had the interpreter in the first line of the script (
#!/bin/bash), since I was explicitly specifying
sh as the interpreter, it was passing my script to
sh. The POSIX compliant
sh, as it turns out, is not as rich as
bash in features and cannot handle process substitution. So I had to ensure that
bash was being used to execute the script, which I achieved by advising the human users not to use
sh and also putting in a check for POSIX compliant execution.
A more detailed resource: http://www.faqs.org/faqs/unix-faq/shell/shell-differences/
Anyway, the point is, something we take for granted could prove quite daunting when it pulls the rug out from under our feet. I hope this information helps someone out someday!