[Bash] Use of brackets in this code snippet

  • Thread starter Thread starter Wrichik Basu
  • Start date Start date
  • Tags Tags
    Code
Click For Summary
SUMMARY

The forum discussion centers on the use of brackets in Bash scripting, specifically within a bubble sort algorithm implementation. The user encountered issues with the correct usage of square brackets, curly brackets, and parentheses. Key insights include the distinction between using double parentheses for arithmetic comparisons and square brackets for logical expressions. Additionally, the user learned that numeric comparisons require operators like -lt and -gt instead of > and <, which are reserved for string comparisons and redirection.

PREREQUISITES
  • Understanding of Bash scripting syntax
  • Familiarity with array manipulation in Bash
  • Knowledge of comparison operators in Bash
  • Basic concepts of control flow in programming
NEXT STEPS
  • Study Bash array syntax and manipulation techniques
  • Learn about Bash arithmetic evaluation using double parentheses
  • Explore logical expressions and their syntax in Bash
  • Review the differences between single quotes and double quotes in Bash
USEFUL FOR

This discussion is beneficial for beginner Bash scripters, computer science students, and anyone looking to understand the intricacies of Bash syntax, particularly in relation to array handling and conditional expressions.

Wrichik Basu
Science Advisor
Insights Author
Gold Member
Messages
2,180
Reaction score
2,690
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   Reactions: 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   Reactions: 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   Reactions: 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   Reactions: 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   Reactions: 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   Reactions: 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   Reactions: Wrichik Basu

Similar threads

  • · Replies 29 ·
Replies
29
Views
3K
  • · Replies 6 ·
Replies
6
Views
2K
  • · Replies 9 ·
Replies
9
Views
3K
  • · Replies 22 ·
Replies
22
Views
3K
  • · Replies 2 ·
Replies
2
Views
2K
  • · Replies 2 ·
Replies
2
Views
2K
  • · Replies 4 ·
Replies
4
Views
2K
Replies
3
Views
2K
  • · Replies 2 ·
Replies
2
Views
3K
  • · Replies 17 ·
Replies
17
Views
4K