bash WTFs

Here is my collection of weird bash features, stuff that doesn't really behave the way i expected it. For short, stuff that made me do "WTF".
$ [[ 8 > 12 ]] && echo true true
Wait what? 8 is more than 12? What happens here is that bash performs a lexicographical comparison and since 8 is bigger than 1 it returns true.
$ (( 8 > 12 )) && echo true
The double brackets cause bash to do arithmetic evaluation inside which > is a math operator. Another feature of arithmetic mode is that you don't have to use the $ to reference variables.
$ var='\' $ var=`echo "$var" | sed 's/\\/\\\\/g'` sed: -e expression #1, char 8: unterminated `s' command
Above is the naive way of trying to replace the backslashes in a variable with sed.. What really happens here is that bash interprets the backslashes once before they get to sed, so what sed get's to see is 's/\/\\/g'. As far as it is concerned the escaped slash is not a delimiter, and since the substitution expect 3 delimiters it throws the error.
$ var='\' $ echo `echo "$var" | sed 's/\\\\/\\\\\\\\/g'` \\ $ echo $(echo "$var" | sed 's/\\/\\\\/g') \\
As you can see the possible solutions to this are either escape the backslashes one more time, or simply use the newer form of command substitution. Why does it interpret the backslashes? Why does $(command) behave differently? Since ksh behaves the same way i'd assume this is a burden of history we have to live with, and with $(command) they are fixing it. This is a documented misfeature.
When the old-style backquote form of substitution is used, backslash retains its literal meaning except when followed by $, `, or \. .. When using the $(command) form, all characters between the parentheses make up the command; none are treated specially.
While we are at backslashes let's try to escape the backslash with awk.
$ echo '\' | awk '{ gsub("\\\\", "replaced"); print; }'
replaced
Wait, what? One would expect that '\\\\' pattern would match '\\'? It turns out this is another documented misfeature, that string is parsed twice and both times the backslashes are interpreted :|.
When using sub, gsub, or gensub, and trying to get literal backslashes and ampersands into the replacement text, you need to remember that there are several levels of escape processing going on.
First, there is the lexical level, which is when awk reads your program and builds an internal copy of it that can be executed. Then there is the runtime level, which is when awk actually scans the replacement string to determine what to generate.
Pipe handling also deserves to be in the WTF category. My thoughts/examples are here while the official docs exaplain this:
Each command in a pipeline is executed in its own subshell
$ time sleep 0.1 &> file real 0m0.106s user 0m0.000s sys 0m0.008s
This is a final WTF :). One would expect that the output of time would go to "file", well, wrong. This is possible because time is a shell keyword and as such can do stuff no other kind (builtins, commands, aliases, functions) in shell ecosystem can do. The positive effect of this kind of behavior is that you can pass time a pipeline and it will time entire pipeline, as opposed to just the first part.
$ { time sleep 0.1; } &> file
$ cat file
real 0m0.108s
user 0m0.004s
sys 0m0.000s
I can't find this documented anywhere in the official docs, it is however documented in BashFAQ
This concludes my list of bash WTFs, if you can think of any more please leave a comment :)
![Reblog this post [with Zemanta]](http://img.zemanta.com/reblog_e.png?x-id=dc6d608e-64fa-4cf4-888c-a3e16cc19f8f)