[Bash] Use of brackets in this code snippet

  • Thread starter Thread starter Wrichik Basu
  • Start date Start date
  • Tags Tags
    Code
AI Thread Summary
The discussion focuses on a beginner's struggle with using brackets in a Bash script for a bubble sort algorithm. Key issues include confusion over the use of different types of brackets, particularly in logical expressions and variable substitutions. It is clarified that double parentheses are required for arithmetic comparisons, while square brackets are for logical conditions, and that numeric comparisons should use operators like -lt or -gt instead of > or <. The conversation also highlights the importance of understanding variable substitution in Bash and how quoting affects command execution. Overall, the thread emphasizes the complexity of Bash scripting and the need for careful attention to syntax.
Wrichik Basu
Science Advisor
Insights Author
Gold Member
Messages
2,180
Reaction score
2,717
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.
[CODE lang="bash" title="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[@]}"[/CODE]
[CODE title="Output"]-13
-1
2
5
7
9
11[/CODE]
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.)
 
Technology news on Phys.org
  • Informative
  • Like
Likes berkeman and jedishrfu
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.
 
  • Like
Likes pbuk, FactChecker and PeterDonis
jedishrfu said:
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.
 
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.
 
  • Like
Likes Wrichik Basu
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.
 
  • Informative
Likes Wrichik Basu
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)
 
  • Like
  • Informative
Likes Wrichik Basu and Ibix
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)​
Read commands from ...
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​
Read commands from 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.​
 
  • Like
Likes Wrichik Basu
Thanks, @Ibix; that also explains why ${arr[i+1]} or similar expressions execute without the need of double parenthesis inside the square brackets.
jedishrfu said:
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.
 
  • #10
I think the < and > re used for input output redirections:

echo "hello world" >somefile.txt

cat <somefile.txt

cat somefile.txt
 
  • Like
Likes Wrichik Basu
Back
Top