2023 UNIX Lecture 5 - Bash Part 2
2023 UNIX Lecture 5 - Bash Part 2
Bash part 2
Nachum Danzig
Spring 5783
Create an array
Indexed Arrays: the keys are ordered integers.
Associative Arrays: the keys are represented by strings.
The -a option creates an indexed array ( here given the name "my_array" ).
Print the keys of an array instead of the values (! only works in conjunction with @ or *)
> my_array=(foo bar)
> for index in "${!my_array[@]}"; do echo "$index"; done
0
1
The same is valid for associative arrays (retrieval order may differ from order in which declared):
> declare -A my_array
> my_array=([foo]=banana [bar]=coconut)
> for key in "${!my_array[@]}"; do echo "$key"; done
bar
foo
ⒸNachum Danzig 2021
Getting the size of an array (number of elements)
> my_array=(foo bar baz)
> echo "the array contains ${#my_array[@]} elements"
the array contains 3 elements
Recall that ${my_array[@]} gives us all the elements of the array. Adding the # character before
the array name, we retrieved the number of the elements in the array instead of its content.
Adding elements to an indexed array with +=
> my_array=(foo bar)
> my_array+=(baz)
> echo "${my_array[@]}"
foo bar baz
Deleting an entire array is simple: we just pass the array name as an argument to the unset
command without specifying any index or key:
> unset my_array
After executing unset against the entire array, when trying to print its content an empty
result is returned: the array doesn't exist anymore.
echo ${#arr2} # size of first element of array, index 0 is default (even if unset)
tmp=${arr2[@]:3} #assign variable tmp all the values in the array from index 3 on
echo ${tmp:0:1} #print variable tmp from index 0, for 1 character length, i.e.4
To copy an array you can iterate over each element, like in C++.
The following will make an array with one element; the declare does not help us.
declare -a q=${arr2[@]}
echo ${q[0]} will print the whole array because the right side of = is just a long
single variable.
We must use ( ) as we would normally define an array of more than one element.
declare -a p=(${arr2[@]})
echo ${p[0]} #prints 123456
ⒸNachum Danzig 2021
Bash test [[ - a new version of test
1. [[ is a syntactical feature of the shell, so it has some special behavior that [ doesn't have. You no longer
have to quote variables like mad because [[ handles empty strings and strings with whitespace more
intuitively. For example, with [ you have to write
if [ -f "$file" ]
to correctly handle empty strings or file names with spaces in them. With [[ the quotes are unnecessary:
if [[ -f $file ]]
2. Because it is a syntactic feature, it lets you use && and || operators for boolean tests and < and > for string
comparisons. [ cannot do this because it is a regular command and &&, ||, <, and > are not passed to regular
commands as command-line arguments.
3. It has a wonderful =~ operator for doing regular expression matches. With [ you might write
if [ "$answer" = y -o "$answer" = yes ]
With [[ you can write this as
if [[ $answer =~ ^y(es)?$ ]]
It even lets you access the captured groups which it stores in BASH_REMATCH. For instance, $
{BASH_REMATCH[1]} would be "es" if you typed a full "yes" above.
4. You get pattern matching aka globbing for free. Maybe you're less strict about how to type yes. Maybe
you're okay if the user types y-anything. It works with the regular = sign.
if [[ $ANSWER = y* ]]
Keep in mind that it is a bash extension, so if you are writing sh-compatible scripts then you need to stick with [. Make
sure you have the #!/bin/bash shebang line for your script if you use double brackets. ⒸNachum Danzig 2021
Bash Test [[ example and an alternative
In old bash (and tcsh) to check for a substring within a string you needed to use
grep like this:
string=”my apple”
if echo “$string” | grep -q “my” ; then
echo “it’s there! “
fi
Newer Bash has [[ which allows regex matching:
string=”my apple”
if [[ $string =~ my ]];
then
echo “ it’s there!”
fi
ⒸNachum Danzig 2021
Jobs
Any program that is suspended (ctrl-z) or running in the background is a job.
You can start a program running in the background by appending an "&" like this:
program &
That program would become a background job. To list all the jobs you are running,
you can use jobs.
A program that is suspended (ctrl-z) can be started up in the foreground (using fg)
or in the background (using bg)
“A job is a concept used by the shell - any program you interactively start that
doesn't detach (i.e., not a daemon) is a job.” -Shawn J. Goff
ⒸNachum Danzig 2021
Command line signals and fg and bg
ctrl-c to stop/kill/interrupt a program running on your shell
bg will also bring the program back to running but it will run in what is called the
background. This means it will not prevent the shell from accepting another
command.
Examples :
ls | xargs file
ls f2 f1 | xargs wc
12 12 38 f1
4 4 22 f2
16 16 60 total
The -0 (zero) option instructs xargs to split its input on null bytes instead of blanks or newlines. Combined
with find's -print0, this allows filenames containing blanks or newlines to be handled properly.
Normally, the command is run once even if there is no input. -r prevents that.
The {} indicate the files found, the ; needs to be back slashed so that the shell
with not attempt to interpret it. I find the xargs version more readable.
But the second version will change the mode of the subdirectories even if they
were previously access denied. xargs will only affect their subdirectory modes if
the directories were previously accessible. (i.e. mode 7 or 5 or 1 )
ⒸNachum Danzig 2021