Bash Script – Unable to Assign Output of Nested Commands to Variable

bashshell-scriptvariable

I was trying to assign below command(which choose the random line from file) to a variable, but not working.

givinv@87-109:~$ head -$((${RANDOM} % `wc -l < file` + 1)) file | tail -1
cower
givinv@87-109:~$

Below the the error I am getting while trying to assign it to a variable.

givinv@87-109:~$ VARIA=`head -$((${RANDOM} % `wc -l < file` + 1)) file | tail -1`
bash: command substitution: line 1: unexpected EOF while looking for matching `)'
bash: command substitution: line 2: syntax error: unexpected end of file
bash: command substitution: line 1: syntax error near unexpected token `)'
bash: command substitution: line 1: ` + 1)) file | tail -1'
-l: command not found
givinv@87-109:~$

I even tried same with for loop and not working::

givinv@87-109:~$ for i in `head -$((${RANDOM} % `wc -l < file` + 1)) file | tail -1`;do echo $i ;done
bash: syntax error near unexpected token `<'
givinv@87-109:~$ 

Best Answer

It's not working because you are attempting to nest unescaped backticks:

VARIA=`head -$((${RANDOM} % `wc -l < file` + 1)) file | tail -1`

That actually attempts to run head -$((${RANDOM} % as a single command first, and that gives you the 2 first errors:

$ VARIA=`head -$((${RANDOM} % `
bash: command substitution: line 1: unexpected EOF while looking for matching `)'
bash: command substitution: line 2: syntax error: unexpected end of file

Then, it tries to run

wc -l < file` + 1)) file | tail -1`

Which means it tries to evaluate + 1)) file | tail -1 (which is between the backticks), and that gives you the next errors:

$ wc -l < file` + 1)) file | tail -1`
bash: command substitution: line 1: syntax error near unexpected token `)'
bash: command substitution: line 1: ` + 1)) file | tail -1'

You can get around this by escaping the backticks:

VARIA=`head -$((${RANDOM} % \`wc -l < file\` + 1)) file | tail -1`

However, as a general rule, it is usually better not to use backticks at all. You should almost always use $() instead. It is more robust and can be nested indefinitely with a simpler syntax:

VARIA=$(head -$((${RANDOM} % $(wc -l < file) + 1)) file | tail -1)
Related Question