0% found this document useful (0 votes)
25 views59 pages

5 CPS393 LinuxOddsEnds

Uploaded by

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

5 CPS393 LinuxOddsEnds

Uploaded by

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

C/CPS 393

Introduction to UNIX, C and C++


Prof. Alex Ufkes

Topic 5: Bash debugging, other odds & ends


Notice!

Obligatory copyright notice in the age of digital


delivery and online classrooms:

The copyright to this original work is held by Alex Ufkes. Students


registered in course C/CPS 393 can use this material for the purposes
of this course but no other use is permitted, and there can be no sale
or transfer or use of the work for any other purpose without explicit
permission of Alex Ufkes.

© Alex Ufkes, 2022 2


Course Administration

Study week is Oct 8-14, no classes or labs!

© Alex Ufkes, 2022 3


Today

Linux
Odds & Ends

© Alex Ufkes, 2022 4


Reading

We can read from files, we can read from the keyboard

read line < fn

Variable to File to read from


read to Using redirection

By default, one line is read at a time from stdin


Returns nonzero value (in $?) if at EOF

© Alex Ufkes, 2022 5


Reading

Returns nonzero value (in $?) if at EOF

tmp is empty
Hits EOF immediately

© Alex Ufkes, 2022 6


Reading from the same file in subsequent
read commands starts from beginning

© Alex Ufkes, 2022 7


Reading

Options:

read -n1 char # read returns after reading 1 character


read -nX chars # read returns after reading X characters

© Alex Ufkes, 2022 8


Reading

Words VS Lines
read arg1 arg2 rest
First word is read into arg1, second word into arg2, the rest of the line into rest

© Alex Ufkes, 2022 9


Reading

read

var="hi there"
echo $var | read x y
echo $x $y #prints nothing!!

echo $var | while read x y ; do


Workaround? echo $x $y #prints hi there
Use a while loop: done
#but $x, $y only have value INSIDE loop

© Alex Ufkes, 2022 10


Reading

echo $var | while read x y ; do


Workaround? echo $x $y #prints hi there
Use a while loop: done
#but $x, $y only have value INSIDE loop

echo $var | (read x y; echo $x $y)


Workaround #2
# prints hi there, but again,
Use subshell:
# $x and $y only have value INSIDE ()

© Alex Ufkes, 2022 11


Reading

Useful example? #!/bin/bash


Ask for forgotten if [ $# -eq 0 ]
arguments:
then
echo "Enter filename"
read fn
else
fn=$1
fi
cp $fn ${fn}.bak
exit 0
© Alex Ufkes, 2022 12
Testing & Debugging

We still have tools at our disposal!


Execute program using bash manually
and add options.

bash -v pgm displays every line of pgm just before executing it


bash -x pgm Like -v but substitutes values of variables in each line

© Alex Ufkes, 2022 13


#!/bin/bash
#Source: findtrunc
# truncates $1 to 8 characters and searches for it in
# hello.txt a msg is printed to indicate if found/not found

trunc=`echo "$1" | cut -c1-8`


if [ "`grep $trunc hello.txt`" ]
then
echo found
else
echo not found
fi

© Alex Ufkes, 2022 14


What happens if we forget the argument?
trunc is nothing, because $1 is nothing
grep searches for hello.txt in stdin

© Alex Ufkes, 2022 15


Terminal is frozen (seemingly)
If you type stuff, hit enter, still nothing happens.
grep is waiting for EOF

hello
world
ctrl-d

© Alex Ufkes, 2022 16


© Alex Ufkes, 2022 17
Use bash -x

We can see the sequence of


commands that caused the issue!
trunc is nothing,
grep is looking for hello.txt

© Alex Ufkes, 2022 18


If we care to make our script robust to this issue, we can add an enclosing if:

© Alex Ufkes, 2022 19


Odds & Ends: shift

#!/bin/bash
#Source: shiftex
#pgm to print its args.
while [ "$1" ] #<--- stops when $1 is null
do
echo "$1" #<--- so spaces preserved
shift #<--- moves $2 to $1, $3 to $2 etc.
done
exit 0

© Alex Ufkes, 2022 20


Odds & Ends: xargs

Takes output of one command, passes as argument into another.


Deceptively similar to pipes, but not the same!
Pipes redirect input, not the same as passing args.

Example: List lines containing 'bash' from all files whose NAME
starts with 'f', where files are located anywhere in the filetree
under current directory

Those files need to be passed into grep as arguments


Redirection using a pipe only applies to a single input source/file

© Alex Ufkes, 2022 21


Odds & Ends: xargs

Example: List lines containing 'bash' from all files whose NAME
starts with 'f', where files are located anywhere in the filetree
under current directory

find . -type f -name "f*" | xargs grep bash

By type: By name:
Find in file starting Output piped into xargs,
current which calls grep with that
directory output as args to grep

© Alex Ufkes, 2022 22


Odds & Ends: xargs

Example: List lines containing 'bash' from all files whose NAME
starts with 'f', where files are located anywhere in the filetree
under current directory

find . -type f -name "f*" | xargs grep bash

Prints LINES in files f* that contain the string bash.


Assuming only such files were ./f1, ./f2, and ./f3, would
end up running: grep bash ./f1 ./f2 ./f3

© Alex Ufkes, 2022 23


find . -type f -name "f*" | xargs grep bash

-VS-
find . -type f -name "f*" | grep bash

The one without xargs is going to grep on the output


stream of find, NOT the files themselves!
It will find file NAMES that contain bash, not file CONTENTS

© Alex Ufkes, 2022 24


Odds & Ends: xargs

find . -type d -empty | xargs rmdir


Find empty directories (use the empty option)
Results of find become arguments to rmdir

ls | xargs
If no command is given to xargs, default is echo
If current dir contains files a, b, c
What ends up running is echo a b c

© Alex Ufkes, 2022 25


Odds & Ends: xargs I{}

The I option runs the command multiple


times, once per item in stdin
{} is substituted in the command for the item

© Alex Ufkes, 2022 26


Odds & Ends: xargs I{}

Another example:

s | xargs -I{} cp {} {}.bak

Make backup copy of all files in current dir.


Assuming current dir contains only entries a, b, c
Runs: cp a a.bak ; cp b b.bak ; cp c c.bak

Note: If there are directories, the copy will fail with a msg
to stderr (can of course redirect 2>/dev/null).
Xargs then just continues with the next item.

© Alex Ufkes, 2022 27


(echo a b c; echo d e; echo f) | xargs -I{} echo :{}:

© Alex Ufkes, 2022 28


Practice Problem

Write a shell program called clean that removes all files


named "core" from your directory structure, and also removes
all files that have size 0 (0 bytes) from your dir structure.
That is your WHOLE dir structure, not just the current dir.
Hint: "find" can find files that are zero bytes long.

© Alex Ufkes, 2022 29


Shell Built-in Commands

are built-in shell commands (echo,


pwd, cd, test, read, etc.)

Just because a command is available in


the shell, does not mean it is a built-in
command

© Alex Ufkes, 2022 30


More Built-ins: eval

Consider the following variable:


v1="cat hello.txt | grep Alex"
Suppose we want to run this
as a command? Try: $v1

cat hello.txt succeeds,


but fails at the |
Because the | is not
recognized as a pipe
© Alex Ufkes, 2022 31
More Built-ins: eval

Consider the following variable:


v1="cat hello.txt | grep Alex"
Use eval instead:

© Alex Ufkes, 2022 32


More Built-ins: eval

Another: v1="cat hello.txt | grep 3"


v2="grep 9 | more "

We want to execute: cat hello.txt | grep 3 | grep 9 | more

$v1 | $v2 | inside v1 and v2 not


recognized as pipes

eval "$v1 | $v2" Eval makes two passes:


1) Make variable substitutions:
eval "cat fn
2) Result evaluated, meta chars etc. interpreted

© Alex Ufkes, 2022 33


More Built-ins: eval

eval "$v1 | $v2"

© Alex Ufkes, 2022 34


This program expects a bunch of command line arguments.
It prompts the user and reads an integer (call it X)
It then prints the Xth command line argument

#!/bin/bash
# Source: printXth
echo -n "enter an integer: "
read X
the_arg='$'${X}
echo "arg number ${X} is: ${the_arg}"
eval echo "arg number ${X} is: ${the_arg}"

note the difference in output:


echo "arg number ${X} is: ${the_arg}"
eval echo "arg number ${X} is: ${the_arg}"

© Alex Ufkes, 2022 35


X is a variable, $X gets us that value
To expand that integer digit as a
variable itself, we need a $ in front.
Hence: the_arg

Like saying: the_arg


Need eval to get the value of $4

© Alex Ufkes, 2022 36


Shell Commands

Shell commands -VS- Built-in commands

Shell commands are built into the shell, available no matter


what happens to be installed on the system.
If we have the shell, we have the built-in commands
Shell commands are found somewhere in the PATH variable.
Usually a bin/ directory of some sort.
Commands built into the shell, VS commands that can be
used in the shell.

© Alex Ufkes, 2022 37


Shell Commands

Shell commands -VS- Built-in commands

echo is both!
The shell recognizes it as a built-in, but the
version of echo that gets called is in /bin
Test this using which:

© Alex Ufkes, 2022 38


Shell Commands

When executing a shell command, the PATH is searched.


If you want to add a folder to your PATH, you can update
the PATH variable like so:

© Alex Ufkes, 2022 39


.bash_profile VS .bashrc

We talked about how .bash_profile executes when


logging into a new shell (via ssh for example)
If you want to add your home dir to your path when
you log in, you can place this in .bash_profile

PATH=${PATH}:${HOME}/bin

.bash_rc, on the other hand, runs when you open a


new terminal window locally.
For example, opening terminal from Ubuntu desktop.
Putty in windows is a login shell (.bash_profile)

© Alex Ufkes, 2022 40


export PATH

PATH=${PATH}:${HOME}/bin
export PATH

Exporting PATH makes it global, so all subsequent


processes spawned in that terminal can access it
Not just the current shell

© Alex Ufkes, 2022 41


Searching PATH

Directories in the PATH variable are checked in order.


Thus, if two folders contain the same command, then the
command from the folder that appears first will execute

For example:
if you write your own rm in ~userid/bin/rm
to use instead of /bin/rm
you must put YOUR ~userid/bin before /bin
in PATH, or /bin/rm will always be executed.

© Alex Ufkes, 2022 42


Searching PATH

PATH=${PATH}:${HOME}/bin
-VS-
PATH=${HOME}/bin:${PATH}

Now your home bin folder appears first.


Of course, you could also just write an alias function!

© Alex Ufkes, 2022 43


More Shell Variables

We know how to set (declare) them:

a=Hello

c=123 →
string containing
digit
123
declare i c=123 →
integer

Using an unset variable does not result


in an immediate runtime error.

© Alex Ufkes, 2022 44


More Shell Variables

Problem:
Referencing a variable before it is assigned a value (programmer error)
It will be null, and the shell program using it may behave unexpectedly

grep "$var" fname

If $var is unset, we get: grep "" fname

fname.
Probably not what you wanted

© Alex Ufkes, 2022 45


More Shell Variables

Error VS null for unset variables?

set u # If any variable unset, referencing it causes error message


set +u # No error message for unset var

Fix previous example:


set u
grep "$var" fname
-bash: var: unbound variable

© Alex Ufkes, 2022 46


© Alex Ufkes, 2022 47
Default Variable Values

${ var:=value }

Place in a script. If variable is not set, it will have the default value.
If the variable was set and exported, it will have set value.

© Alex Ufkes, 2022 48


Default Variable Values

DO NOT RUN THIS!!

What does this do

[
if $temp

""
"
•, ,
↳ win naming
ad .

© Alex Ufkes, 2022 49


cd without an argument takes
you to your home directory
If $temp is not set, what
happens when we do cd $temp
erase your home directory
and all its contents

© Alex Ufkes, 2022 50


Default Variable Values

Fix using default variable value:

test -d ~/tmp || mkdir ~/tmp


cd ${temp:=~/tmp}
rm *
cd ..
rmdir $temp

Clunky, but at least this way if you accidentally unset $temp,


it erases a newly created directory called ~/tmp

© Alex Ufkes, 2022 51


Default Variable Values

Cleaner, using if in a script:


of

another
way command
test is

if [ -
cd $temp
rm *
cd ..
rmdir $temp
fi

© Alex Ufkes, 2022 52


More fun with set

We can set manually. Good for iteration:

set "val1" "val2"... #sets $1 to "val1", $2 to "val2" ...

set - * # Sets $1, $2, $3 ... to all files in current directory

Expands as Glob construct

© Alex Ufkes, 2022 53


© Alex Ufkes, 2022 54
Here Documents

while [ true ]
do Use string between here tags as input to cat.
clear Notice the << redirection
cat << here
MAIN MENU
1) Print working dir.
2) List all entries in current dir.
3) Print date & time
4) Display contents of file
X) Exit
here

© Alex Ufkes, 2022 55


character does get executiveed new line is omitted
escape so .

echo -e "Please enter selection ${LOGNAME}: \c"



read selection username

case $selection in
while [ true ] 1) pwd ;;
do
2) ls ;;
clear
cat << here 3) date ;;
MAIN MENU 4) echo -e "Enter a file name: \c"
file
1) Print working dir. read fname
a
.

it is
it
-
2) List all entries in current dir.
if [ -f $fname ]; then
3) Print date & time
4) Display contents of file echo "Contents of $fname are: "
X) Exit more $fname
here else
echo "file $fname does not exist"
fi ;;
X) exit 0 ;;
*) echo -e "Invalid choice. Try again \a" ;;
esac
echo -e "\n Press return to continue \c"
read hold
done
© Alex Ufkes, 2022 exit 0 56
© Alex Ufkes, 2022 57
© Alex Ufkes, 2022 58
© Alex Ufkes, 2022 59

You might also like