# [Bash] Use of brackets in this code snippet

Gold Member
2020 Award
Disclaimer: I am an absolute beginner in bash scripting.

I spent the whole evening trying to make this code snippet work as intended. The program is supposed to sort an array using bubble sort algorithm.
Program:
#!/bin/bash

arr=(7 -1 9 2 11 -13 5)

for (( i=0; i<(( ${#arr[@]} - 1 )); i++ )) ; do for (( j=0; j<((${#arr[@]} - 1 - i )); j++ )); do
if (( arr[j] > arr[j+1] )); then
temp=${arr[j]} arr[j]=${arr[j+1]}
arr[j+1]=${temp} fi done done echo -ne "\n" printf '%s\n' "${arr[@]}"
Output:
-13
-1
2
5
7
9
11
I knew the algorithm well; the only problem I faced was brackets. Curly brackets, parenthesis, square brackets — all got mixed up. Later, I found this question on Stack Overflow that outlines the different brackets and their meanings. That solves most of the queries, but some remain:
1. Square brackets, [[...]] are used for logical expressions. Then why does neither if [[ arr[j] > arr[j+1] ]] nor if [[ ${arr[j]} >${arr[j+1]} ]] work? (On the other hand, both if (( ${arr[j]} >${arr[j+1]} )) and if (( arr[j] > arr[j+1] )) works.)
2. I found that I get the correct output even if I don't use $ in front of i and j. If bash can substitute the value of the variable here, why can't it do the same in other places? (For example, in lines 8, 9 and 10, I have to use ${...} on the RHS of the = operator.)

berkeman and jedishrfu
jedishrfu
Mentor
Most bash scripters when faced with what you’re doing will quickly shift to python to get it done.

Bash is great for simple scripting and extremely dense for more complex stuff.

pbuk, FactChecker and PeterDonis
Gold Member
2020 Award
Most bash scripters when faced with what you’re doing will quickly shift to python to get it done.
I am doing it because I have to do it for my computer science elective this semester. Given a choice, I would have certainly chosen Java in most cases.

jedishrfu
Mentor
I understand, I was just giving you my experience. I’ve tried to extend some scripts ans the peculiarities of bash always get in the way usually around single quotes vs double quotes.

Wrichik Basu
Ibix
2020 Award
Regarding OP's question 2 - I believe that you don't need the $signs in front of variables when they are used in mathematical expressions. Presumably array indices count as mathematical expressions, hence ${arr[i]} not needing a dollar before the i.

I don't think it's a case of bash not being able to substitute a variable value, but that you don't want it to substitute a value unless you explicitly tell it to (or use the variable in a mathematical context where it's clear it should be used as a variable). Remember that this is a shell script - it's largely used to run operating system commands. So say you define a variable called ls. What do you want bash to do with the characters ls - interpret them as a variable and fetch the value, or execute the ls command? You could make known Unix commands reserved words, but you can't write an exhaustive list of programs you could be running so you would always risk a collision. Bash solves the problem allowing variable names to be (almost) anything and requiring you to write $ls to get the value of the variable. Wrichik Basu jedishrfu Mentor The single quote double quote issue is that single quotes are for literals ie no substitutions echo "The book title is:$1" (prints the first script arg remember $0 is the script name itself) vs echo 'The book cost:$1' (prints the literal 'the book cost $1') For some commands you want the delayed expansion of a file mask as in the command find . -name '*.jpg' (to find all jpg files with the current directory tree) Wrichik Basu and Ibix jedishrfu Mentor The best script development strategy is to use echo statements to see what happens and to add your changes slowly and carefully, testing in between to make sure things are working as you expect. I think bash also has a no-execute flag where the script will display with substitutions and adjustments but not execute and commands. as in bash -n for noexecute: https://tldp.org/LDP/abs/html/options.html Table 33-1. Bash options Abbreviation​ Name​ Effect​ -B​ brace expansion​ Enable brace expansion (default setting = on)​ +B​ brace expansion​ Disable brace expansion​ -C​ noclobber​ Prevent overwriting of files by redirection (may be overridden by >|)​ -D​ (none)​ List double-quoted strings prefixed by$, but do not execute commands in script​
-a​
allexport​
Export all defined variables​
-b​
notify​
Notify when jobs running in background terminate (not of much use in a script)​
-c ...​
(none)​
checkjobs​
Informs user of any open jobs upon shell exit. Introduced in version 4 of Bash, and still "experimental." Usage: shopt -s checkjobs (Caution: may hang!)​
-e​
errexit​
Abort script at first error, when a command exits with non-zero status (except in until or while loops, if-tests, list constructs)​
-f​
noglob​
Filename expansion (globbing) disabled​
globstar​
Enables the ** globbing operator (version 4+ of Bash). Usage: shopt -s globstar​
-i​
interactive​
Script runs in interactive mode​
-n
noexec
Read commands in script, but do not execute them (syntax check)
-o Option-Name​
(none)​
Invoke the Option-Name option​
-o posix​
POSIX​
Change the behavior of Bash, or invoked script, to conform to POSIX standard.​
-o pipefail​
pipe failure​
Causes a pipeline to return the exit status of the last command in the pipe that returned a non-zero return value.​
-p​
privileged​
Script runs as "suid" (caution!)​
-r​
restricted​
Script runs in restricted mode (see Chapter 22).​
-s​
stdin​
-t​
(none)​
Exit after first command​
-u​
nounset​
Attempt to use undefined variable outputs error message, and forces an exit​
-v​
verbose​
Print each command to stdout before executing it​
-x​
xtrace​
Similar to -v, but expands commands​
-​
(none)​
End of options flag. All other arguments are positional parameters.​
--​
(none)​
Unset positional parameters. If arguments given (-- arg1 arg2), positional parameters set to arguments.​

Wrichik Basu
Gold Member
2020 Award
Thanks, @Ibix; that also explains why ${arr[i+1]} or similar expressions execute without the need of double parenthesis inside the square brackets. The single quote double quote issue is that single quotes are for literals ie no substitutions I haven't used parameterized functions yet, but was hoping to use them soon. Thanks for pointing out this subtlety; otherwise I would have had to spend hours not realizing where the error is occurring. Also, I have made one error in the program: > or < cannot be used for numeric comparisons; they are for strings. Instead, I have to use -lt or -gt and so on. An interesting note regarding question no. 1: the following works: if [[ (${arr[j]} -gt \${arr[j+1]} ) ]];, which probably means I have to evaluate the expression inside a subshell to make it work.

jedishrfu
Mentor
I think the < and > re used for input output redirections:

echo "hello world" >somefile.txt

cat <somefile.txt

cat somefile.txt

Wrichik Basu