0% found this document useful (0 votes)
14 views17 pages

2023 UNIX Lecture 5 - Bash Part 2

This document provides an overview of arrays in Bash, including how to create, manipulate, and delete indexed and associative arrays. It also covers the use of the '[[ ]]' test command for more intuitive string handling and regex matching, as well as job control commands like 'fg' and 'bg'. Additionally, it discusses the 'xargs' command for executing commands based on input from standard input.

Uploaded by

Meir Shaanani
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PPTX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
14 views17 pages

2023 UNIX Lecture 5 - Bash Part 2

This document provides an overview of arrays in Bash, including how to create, manipulate, and delete indexed and associative arrays. It also covers the use of the '[[ ]]' test command for more intuitive string handling and regex matching, as well as job control commands like 'fg' and 'bg'. Additionally, it discusses the 'xargs' command for executing commands based on input from standard input.

Uploaded by

Meir Shaanani
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PPTX, PDF, TXT or read online on Scribd
You are on page 1/ 17

Unix Systems Lecture 5

Bash part 2

Nachum Danzig
Spring 5783

ⒸNachum Danzig 2021


Arrays in Bash from /linuxconfig.org with of my some changes

Create an array
Indexed Arrays: the keys are ordered integers.
Associative Arrays: the keys are represented by strings.

Create indexed or associative arrays by using declare


Use the declare command:
> declare -a my_array

The -a option creates an indexed array ( here given the name "my_array" ).

Use the -A option of the declare command to create an associative array:


> declare -A my_array

Using declare -A is the only way to create associative arrays in bash.

ⒸNachum Danzig 2021


Examples of Associative and Indexed Arrays
declare -A my_array

my_array=([banana]=yellow [coconut]=brown [lemon]=yellow)

my_array[papaya]=green #insert one value specifying its key

declare -a my_array #optional

my_array = (banana coconut lemon)

my_array[3] = papaya #insert one value specifying its index


ⒸNachum Danzig 2021
Array operations
Print the values of an array
To display all the values of an array, use the following shell expansion syntax:
> echo ${my_array[@]}
Or even:
> echo ${my_array[*]}
Both syntax let us access all the values of the array and produce the same results, unless the expansion
is quoted. In this case a difference arises: in the first case, when using @, the expansion will result in a
word for each element of the array. This becomes immediately clear when performing a for loop. As an
example, imagine we have an array with two elements, "foo" and "bar":
> my_array=(foo bar)
Performing a for loop on it will produce the following result:
> for i in "${my_array[@]}"; do echo "$i"; done
foo
bar
But when using *, and the variable is quoted, a single "result" will be produced, containing all the
elements of the array:
> for i in "${my_array[*]}"; do echo "$i"; done
foo bar
ⒸNachum Danzig 2021
It is also possible to iterate over part of an array with the new (( )) operator, like this:
C-style for loops
for (( i=0; $i < ${#my_array[@]}; i+=1 )); do
echo ${my_array[$i]}
done
foo
bar

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

Multiple elements can be added at a time:


> my_array=(foo bar)
> my_array+=(baz foobar)
> echo "${my_array[@]}"
foo bar baz foobar
ⒸNachum Danzig 2021
To add elements to an associative array, we must specify their associated keys:
> declare -A my_array
> my_array[foo]="bar"
# Add multiple elements at a time
> my_array+=([baz]=foobar [foobarbaz]=baz)

Deleting an element from the array only by its index


> my_array=(foo bar baz)
> unset my_array[1]
> echo ${my_array[@]}
foo baz
Bash arrays start at 0. If we check the indexes of the array, we can now see that 1 is missing:
> echo ${!my_array[@]}
0 2
The same thing is valid for associative arrays:
> declare -A my_array
> my_array+=([foo]=bar [baz]=foobar)
> unset my_array[foo]
> echo ${my_array[@]}
foobar ⒸNachum Danzig 2021
Deleting an array

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

> echo ${!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.

ⒸNachum Danzig 2021


Array Examples in bash
arr2=(123456 234 6544 4545 5454) # declare an array, -a is default

echo ${#arr2[@]} # size of array

echo ${#arr2[2]} # size (length) of element at index number 2

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 # print 4545 5454, tmp is a variable, not an array

echo ${tmp:0:1} #print variable tmp from index 0, for 1 character length, i.e.4

tmp=(${arr2[@]:3}) # this will create tmp as an array of two elements


ⒸNachum Danzig 2021
Printing section of an array and Copying an array
arr2=(123456 234 654 4545 5454)
echo ${arr2[@]:2:2} # print 654 4545, i.e. from index 2, 2 elements

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

ctrl-z to suspend a program running in your shell.

fg will bring the program back to running

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.

program & will also run the program in the background

Question: What does fg stand for?


ⒸNachum Danzig 2021
xargs
xargs - reads items from the standard input, delimited by blanks or newlines, and
executes the command (default is /bin/echo) one or more times with any initial-
arguments followed by items read from standard input.

Examples :

ls | xargs file

find /tmp -name core -type f -print | xargs /bin/rm -f

ⒸNachum Danzig 2021


More xargs
ls f2 f1 | wc
2 2 6

ls f2 f1 | xargs wc
12 12 38 f1
4 4 22 f2
16 16 60 total

find . -type f | xargs grep "george"

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.

find . -type f -print0 | xargs -0r grep "george"


ⒸNachum Danzig 2021
find -exec vs. xargs
Using xargs I could do the following

find . -type d | xargs chmod 755

Can also be done by find itself like this:

find . -type d -exec chmod 755 {} \;

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

You might also like