1
00:00:03,350 --> 00:00:06,950
This lesson you'll learn how to use functions in your scripts.

2
00:00:06,990 --> 00:00:13,350
First off a function is simply a group of commands that you call using a single name in your script.

3
00:00:13,470 --> 00:00:18,120
You can think of functions as being little scripts inside of your main script.

4
00:00:18,180 --> 00:00:24,980
You can call or execute a function just like you would any other script or command on a Linux system.

5
00:00:25,260 --> 00:00:30,180
There are a couple of reasons why you would want to use a functions.

6
00:00:30,180 --> 00:00:37,470
The first reason is that you don't want to have duplicate code in multiple places in your script using

7
00:00:37,500 --> 00:00:41,380
functions allows your code to remain dry dry.

8
00:00:41,380 --> 00:00:46,130
Is a computer programming an application development principle that stands for.

9
00:00:46,170 --> 00:00:47,910
Don't repeat yourself.

10
00:00:48,000 --> 00:00:54,060
Functions allow you to write a block of code once and use it many times instead of repeating several

11
00:00:54,060 --> 00:00:59,670
lines of code each time you need to perform a particular task simply call the function that contains

12
00:00:59,670 --> 00:01:00,690
that code.

13
00:01:00,690 --> 00:01:07,470
This helps in reducing the length of your scripts and also gives you a single place to change test troubleshoot

14
00:01:07,500 --> 00:01:09,950
and document a given task.

15
00:01:09,960 --> 00:01:13,380
All of this makes your scripts easier to maintain.

16
00:01:14,350 --> 00:01:21,010
By the way there is a counter principle called wet which stands for write everything twice or we enjoy

17
00:01:21,010 --> 00:01:24,220
typing or waste everyone's time.

18
00:01:24,220 --> 00:01:30,520
If you catch yourself typing out this same bit of code or you find yourself copying and pasting existing

19
00:01:30,520 --> 00:01:35,680
code in your script it's time to dry up that wet code and use a function.

20
00:01:35,680 --> 00:01:42,530
The second reason to use functions is to break up large tasks into a series of smaller tasks.

21
00:01:42,730 --> 00:01:45,600
This makes your code easier to maintain.

22
00:01:45,610 --> 00:01:51,580
You can zoom into a function that only does one small thing and make your changes around that small

23
00:01:51,580 --> 00:01:52,550
thing there.

24
00:01:52,600 --> 00:01:54,880
And that one place.

25
00:01:54,880 --> 00:02:00,850
For example if you are using a case statement to make a decision then instead of writing a whole long

26
00:02:00,850 --> 00:02:06,870
block of code inside the case statement you could call a function that actually does the real work.

27
00:02:06,880 --> 00:02:08,740
All right so enough philosophizing.

28
00:02:08,740 --> 00:02:12,040
Let's get to work and start creating some functions.

29
00:02:12,040 --> 00:02:14,900
So first off here as always I have my terminal open.

30
00:02:14,980 --> 00:02:18,490
I'm going to change into our class folder of shell class.

31
00:02:18,490 --> 00:02:20,530
We're still working on the locals.

32
00:02:20,530 --> 00:02:22,380
Users of vagrant project.

33
00:02:22,600 --> 00:02:37,030
And now I'm going to bring up this VM with vagrant up.

34
00:02:37,160 --> 00:02:40,960
One way to create a function is to use the function built in command.

35
00:02:42,980 --> 00:02:44,680
Here you start with the word function.

36
00:02:44,690 --> 00:02:50,440
Give your function a name then surround a series of commands inside curly braces.

37
00:02:50,600 --> 00:02:54,470
The other way you can create a function is to give your function a name.

38
00:02:54,590 --> 00:03:00,440
Follow it with a set of parentheses then surround a series of commands inside curly braces.

39
00:03:00,440 --> 00:03:03,200
Now let's jump into a script and try it out.

40
00:03:06,310 --> 00:03:11,520
Let's create a function called log that will end up logging messages to the system log and optionally

41
00:03:11,530 --> 00:03:18,100
displaying those messages to the user executing the script will iterate over this bit of code and keep

42
00:03:18,100 --> 00:03:25,470
going as we go but we'll start out here will create a function by providing the name.

43
00:03:25,520 --> 00:03:30,260
Then following that name with parentheses and then we're going to create a block of code surrounded

44
00:03:30,260 --> 00:03:33,600
in curly braces here and we'll just do this for now.

45
00:03:33,600 --> 00:03:41,790
Echo you call the log function and end it with a closing curly brace.

46
00:03:41,880 --> 00:03:48,420
Now a color will just use the word log and that will execute it just like any other command on a Linux

47
00:03:48,420 --> 00:03:49,340
system.

48
00:03:49,350 --> 00:03:54,360
Now remember that scripts get read and executed from the top down.

49
00:03:54,360 --> 00:03:57,420
That means you have to define a function before you can use it.

50
00:03:57,420 --> 00:04:01,460
That's why we define the log of function at the top of your script here.

51
00:04:01,560 --> 00:04:08,430
When a function is defined it is read into memory and it's then available for use.

52
00:04:08,490 --> 00:04:15,020
The code in the function is just remembered initially and it's only executed when it gets called.

53
00:04:15,030 --> 00:04:19,290
Notice that when we called the function we didn't use the parentheses.

54
00:04:19,320 --> 00:04:24,000
You may have seen this type of syntax and style and other programming languages where you actually use

55
00:04:24,000 --> 00:04:27,360
the parentheses but it doesn't work in shell scripts.

56
00:04:27,360 --> 00:04:32,310
Simply place the name of a function on a line and it will execute that function.

57
00:04:32,310 --> 00:04:33,760
So let's try it out.

58
00:04:38,380 --> 00:04:43,180
Hey sure enough we get the output that says you call the log function.

59
00:04:43,630 --> 00:04:47,950
Hey that's not very interesting yet but we'll get there soon enough so let's get back into our script

60
00:04:47,950 --> 00:04:48,940
here.

61
00:04:48,940 --> 00:04:54,220
I want to show you the other way you can define a function so how you can do that is use the keyword

62
00:04:54,220 --> 00:04:55,130
function.

63
00:04:55,390 --> 00:04:57,620
All that by your function name.

64
00:04:57,740 --> 00:05:03,220
And then you don't need the parentheses here and will save our changes and test this as well.

65
00:05:03,460 --> 00:05:07,490
So as you can see it also works so either method works.

66
00:05:07,510 --> 00:05:11,340
I'm going to go back and use this particular style here.

67
00:05:12,330 --> 00:05:16,370
Now let's make our log function display to the screen whatever is passed to it.

68
00:05:16,560 --> 00:05:20,050
So I'll type out the code here and then we'll talk through it in just a second.

69
00:05:20,310 --> 00:05:22,680
So what we're going to do here is this.

70
00:05:52,910 --> 00:06:00,140
I've introduced a new show built in called Local what local does is makes a variable local in scope

71
00:06:00,200 --> 00:06:01,490
to the function.

72
00:06:01,490 --> 00:06:07,280
That means the value of that variable is only accessible inside that function.

73
00:06:07,280 --> 00:06:13,490
So in this example if you tried to display the contents of the message a variable before or after the

74
00:06:13,490 --> 00:06:16,460
function it would be blank and unset.

75
00:06:16,490 --> 00:06:20,360
That's because it only exists inside the function.

76
00:06:20,390 --> 00:06:25,860
By the way the local command can only be used inside a function that's the only place it makes sense.

77
00:06:26,000 --> 00:06:32,750
And the reason why is that until now we've been using global variables and that means that the variable

78
00:06:32,750 --> 00:06:39,770
and its contents or its value can be accessed anywhere in the script including in any function.

79
00:06:39,770 --> 00:06:44,090
Now we haven't been using functions until now so it really didn't matter until this point.

80
00:06:44,210 --> 00:06:50,450
By the way if you define a global variable in a function by omitting the local keyword in front of it

81
00:06:50,780 --> 00:06:57,290
that global variable is not available outside that function until the function is called and executed

82
00:06:57,760 --> 00:07:01,780
it's not a best practice to do that anyway so it shouldn't really be an issue.

83
00:07:01,970 --> 00:07:07,910
However when you are using functions just be aware of the scope of each variable and know that it can

84
00:07:07,910 --> 00:07:12,410
be a place that can deserve some attention when troubleshooting your scripts.

85
00:07:12,470 --> 00:07:16,520
It's a best practice to use local variables inside your functions.

86
00:07:16,520 --> 00:07:22,370
That way you won't accidentally reuse the same variable name in another function and end up with a tricky

87
00:07:22,370 --> 00:07:23,090
bug.

88
00:07:23,090 --> 00:07:28,160
However you'll find plenty of shell scripts that do not add here to this recommendation.

89
00:07:28,190 --> 00:07:30,440
Most of the time it will not cause a problem.

90
00:07:30,440 --> 00:07:35,210
Just be sure to use unique variable names throughout your script and you'll be fine.

91
00:07:35,210 --> 00:07:40,710
Now let's talk about the value that is assigned to the local variable named message.

92
00:07:40,730 --> 00:07:46,280
It's our old friend dollar sign and sign back from our positional parameters lesson as you recall a

93
00:07:46,280 --> 00:07:53,270
dollar sign at sign expands to all the positional parameters starting from one functions act like a

94
00:07:53,270 --> 00:07:59,000
script within your script and you can accept arguments which can be then accessed as positional parameters

95
00:07:59,060 --> 00:08:00,730
inside the function.

96
00:08:00,830 --> 00:08:04,920
For example the first argument passed to a function is dollar sign one.

97
00:08:04,940 --> 00:08:07,750
The second is Dollar Sign 2 and so on.

98
00:08:07,760 --> 00:08:13,850
The only difference between a function and a script here is that dollar sign is zero is still the name

99
00:08:13,850 --> 00:08:17,640
of the shellscript itself and not the name of the function.

100
00:08:17,660 --> 00:08:20,650
Even if you're using dollar signs zero in the function.

101
00:08:20,840 --> 00:08:26,210
And that's really OK anyway because you'd never really want to use that functionality anyway.

102
00:08:26,570 --> 00:08:28,620
OK let's try this bit of code out.

103
00:08:31,240 --> 00:08:36,880
When we execute our script the function is called first time with Hello it print the screen the second

104
00:08:36,880 --> 00:08:38,650
time the function is called with.

105
00:08:38,650 --> 00:08:42,710
This is fun and that also gets displayed to the screen.

106
00:08:43,240 --> 00:08:47,720
Now let's update our function to only display the message that was passed to it.

107
00:08:47,770 --> 00:08:52,110
If a global variable named verbose is set to true

108
00:09:02,740 --> 00:09:11,090
so will check to see if both is true and if it is then will echo that message to the screen and the

109
00:09:11,090 --> 00:09:14,090
ephi there closes out our IF statement.

110
00:09:14,150 --> 00:09:21,650
So let's do this let's call our function log with hello and then let's go ahead and now set verbose

111
00:09:22,040 --> 00:09:23,230
equal to true.

112
00:09:23,240 --> 00:09:28,010
So the first time we call a function rebozo is not set the second time we call it.

113
00:09:28,070 --> 00:09:30,270
It is set to true.

114
00:09:30,380 --> 00:09:36,860
Now this function is actually starting to become useful if we didn't have this function then we would

115
00:09:36,860 --> 00:09:43,250
have to test for the value of the verbose variable every single time we needed to decide if we wanted

116
00:09:43,250 --> 00:09:45,530
to display something to the screen or not.

117
00:09:45,530 --> 00:09:50,170
This means we would end up with a lot of duplicate code throughout our script.

118
00:09:50,180 --> 00:09:56,180
In any case what should happen is that the text below will not be displayed to the screen because verbose

119
00:09:56,180 --> 00:10:01,970
has not been set to true at that point and the text this is Vonne will be displayed because as I just

120
00:10:01,970 --> 00:10:08,460
explained verbose is set to true before log is called with that particular text passed into it.

121
00:10:08,460 --> 00:10:10,620
So let's try that out.

122
00:10:13,730 --> 00:10:18,670
Hey sure enough Hello was not displayed to the screen but this is fun.

123
00:10:18,690 --> 00:10:20,710
Was just as we expected.

124
00:10:21,780 --> 00:10:27,150
If you've ever had any formal training in computer programming you've probably heard that global variables

125
00:10:27,150 --> 00:10:30,650
are evil and you should avoid them at all costs.

126
00:10:30,660 --> 00:10:36,060
Really what you should try to avoid at all costs are the problems that can arise by using global variables

127
00:10:36,060 --> 00:10:40,710
such as different functions changing the value of a global variable and so on.

128
00:10:40,710 --> 00:10:46,020
Now I'm a pretty pragmatic person so I like to do what is best for a given situation.

129
00:10:46,020 --> 00:10:52,410
In that vein let me give you an example of why avoiding global variables can be less than ideal especially

130
00:10:52,410 --> 00:10:54,850
with our little use case here.

131
00:10:54,900 --> 00:11:01,410
We could change this function such that it doesn't rely on the verbose global variable and instead make

132
00:11:01,410 --> 00:11:04,830
it an argument that has to be passed into the function.

133
00:11:04,830 --> 00:11:06,420
So what we can do is this.

134
00:11:06,420 --> 00:11:14,310
We can add local verb Bowse and set that to the value that is passed into it here.

135
00:11:14,380 --> 00:11:21,070
The first value that's passed into it then we'll use shift here and then at that point every thing else

136
00:11:21,070 --> 00:11:22,350
stays the same.

137
00:11:22,360 --> 00:11:28,100
So what this does is assigns the first value passed into the function into the local variable named

138
00:11:28,140 --> 00:11:29,090
verbose.

139
00:11:29,140 --> 00:11:34,490
Then the shift command shifts all those positional parameters which removes the value stored in Dallas

140
00:11:34,500 --> 00:11:36,870
and one makes dollar sign to dollar sign.

141
00:11:36,870 --> 00:11:40,120
One makes the dollar sign three dollar sign too and so on.

142
00:11:40,120 --> 00:11:46,930
So more or less we chop off the value we assigned to verbose and what we're left with is the message

143
00:11:46,960 --> 00:11:49,210
that was passed into the function.

144
00:11:49,210 --> 00:11:52,120
Now we have to update how we call this function.

145
00:11:52,180 --> 00:11:59,350
So here we're going to do log true to tell it that we're going to be verbose and we can get rid of this

146
00:11:59,350 --> 00:12:00,650
piece of code here.

147
00:12:00,880 --> 00:12:05,330
And we're also going to do this we'll say true here as well.

148
00:12:05,380 --> 00:12:11,350
Now every time we use the log function we need to tell it if we want verbose to be true or false.

149
00:12:11,380 --> 00:12:18,520
Of course we could set a variable and use that like this so we can do this we could say verbosity is

150
00:12:18,520 --> 00:12:22,300
true and then we'll do this

151
00:12:31,720 --> 00:12:32,700
OK.

152
00:12:33,160 --> 00:12:38,400
In practice the verbosity is going to remain the same for our entire script because of that.

153
00:12:38,410 --> 00:12:43,930
I could argue that passing it into the function every single time is causing us to repeat ourselves

154
00:12:43,930 --> 00:12:46,850
without any real practical gain.

155
00:12:46,870 --> 00:12:49,960
In this example I think using a global variable is fine.

156
00:12:49,960 --> 00:12:53,830
However if you disagree with me that's also fine in my opinion.

157
00:12:53,830 --> 00:12:55,670
Both methods are correct.

158
00:12:55,720 --> 00:12:59,250
So long as they get the job done successfully.

159
00:12:59,260 --> 00:13:04,480
Now let's just show that this little piece of code works so we'll see where changes and execute our

160
00:13:04,480 --> 00:13:13,530
script and sure enough it executes the function and displays what we passed to it to the screen if we

161
00:13:13,530 --> 00:13:18,690
were doing something like differentiating informational messages from morning messages from critical

162
00:13:18,690 --> 00:13:24,950
messages then passing in that log level would make sense because it can change throughout her script.

163
00:13:24,960 --> 00:13:27,750
So again use what works and what makes sense to you.

164
00:13:27,750 --> 00:13:29,490
Just make sure that it actually works.

165
00:13:29,490 --> 00:13:31,170
Test your scripts.

166
00:13:31,230 --> 00:13:36,690
Now let's revert our code and handle the main concern of using global variables within functions which

167
00:13:36,690 --> 00:13:41,430
is that a function might actually change the value of that global variable.

168
00:13:41,610 --> 00:13:42,500
So we'll do this

169
00:13:59,340 --> 00:14:04,950
the read only shell builtin makes a variable unchangeable or an modifiable.

170
00:14:04,950 --> 00:14:10,500
This is the shells version of a constant variable which is a term you might be familiar with if you've

171
00:14:10,500 --> 00:14:12,230
programmed in other languages.

172
00:14:12,540 --> 00:14:15,620
There are two ways to use the read only shell built in.

173
00:14:15,630 --> 00:14:20,150
One is just like we have it here on the screen which is to use the word read only.

174
00:14:20,160 --> 00:14:25,520
Followed by the variable and then include the variable assignment there right after it.

175
00:14:25,530 --> 00:14:31,350
The other way is to perform the variable assignment first and then use Read-Only followed by just the

176
00:14:31,350 --> 00:14:32,420
variable name.

177
00:14:32,490 --> 00:14:36,770
There's no need to include the assignment because it's already performed at that point.

178
00:14:36,780 --> 00:14:42,280
This way you can separate the setting of the variable and marking it as read only.

179
00:14:42,570 --> 00:14:47,640
Now that the verbose variable is read only it cannot be changed for the duration of the script.

180
00:14:47,760 --> 00:14:51,610
That means it cannot be changed inside or outside of a function.

181
00:14:51,690 --> 00:14:56,270
That eliminates a concern about a function changing the value of a global variable.

182
00:14:56,610 --> 00:15:01,920
OK we've taken care of the first bit of our function that controls whether or not we display a message

183
00:15:01,920 --> 00:15:03,110
to standard output.

184
00:15:03,270 --> 00:15:08,700
Now let's write the last little piece that will control sending messages to the system's log.

185
00:15:08,700 --> 00:15:12,150
To do that we'll use a command line utility named logger.

186
00:15:12,150 --> 00:15:15,270
Let's actually take a look at that on the command line.

187
00:15:19,470 --> 00:15:19,850
OK.

188
00:15:19,880 --> 00:15:26,010
Logger is a executable so we can run man against that to get some information about that particular

189
00:15:26,010 --> 00:15:26,720
command.

190
00:15:27,700 --> 00:15:34,060
Mainly you just supply logger a message and that message is recorded and the systems log by default

191
00:15:34,060 --> 00:15:35,920
on a Sentosa rail system.

192
00:15:35,920 --> 00:15:39,910
Those messages will go to the var log messages file.

193
00:15:39,910 --> 00:15:44,680
You can read all the details here if you like but I'm just going to point out the one bit of information

194
00:15:44,680 --> 00:15:51,940
we're going to use most immediately and that is the dash t option which allows you to tag your Ciss

195
00:15:51,970 --> 00:16:00,720
log message on the move down here to Dashti this tag is typically set to the name of your program or

196
00:16:00,720 --> 00:16:03,880
the program that is writing to the system log file.

197
00:16:03,960 --> 00:16:05,430
So let's try that out now.

198
00:16:05,460 --> 00:16:08,870
Q To get out of this help and we'll do this longer.

199
00:16:10,290 --> 00:16:13,660
From the command line.

200
00:16:13,740 --> 00:16:14,100
All right.

201
00:16:14,100 --> 00:16:20,610
And we want to look at the var log messages file and that file happens to have permission such that

202
00:16:20,610 --> 00:16:22,500
we need to read that file.

203
00:16:26,230 --> 00:16:33,400
And as you can see there the last line of that log file is what we sent to it with the logger command.

204
00:16:33,400 --> 00:16:39,940
The format of these Assis log messages is a time stamp followed by the computer name followed by the

205
00:16:39,940 --> 00:16:44,330
tag which is again most often the name of the program writing to this log.

206
00:16:44,350 --> 00:16:47,640
In this case it's our username since we didn't specify a tag.

207
00:16:47,830 --> 00:16:49,930
And finally the message itself.

208
00:16:49,930 --> 00:16:55,540
So this time let's add a tag will do logger Dashti my script.

209
00:16:55,930 --> 00:16:59,850
Tagging on.

210
00:16:59,860 --> 00:17:05,360
So this time you can see that the tag reads my script and then we see the message that we passed into

211
00:17:05,390 --> 00:17:06,040
that.

212
00:17:06,190 --> 00:17:12,250
By the way since law can be configured to send messages off the server and to a centralized assist log

213
00:17:12,250 --> 00:17:13,940
location for example.

214
00:17:13,990 --> 00:17:19,000
Now I cover the details of exactly how to do this in my Linux in the real world course.

215
00:17:19,040 --> 00:17:24,660
Anyway that is a good security measure because if someone were to have root access to one system in

216
00:17:24,690 --> 00:17:30,490
the logs that they generated are not only stored locally where they could potentially change them or

217
00:17:30,490 --> 00:17:36,430
delete them but they're also stored on a remote system where hopefully that person or that attacker

218
00:17:36,430 --> 00:17:38,900
hasn't broken into that system as well.

219
00:17:39,100 --> 00:17:44,350
It's just something to keep in mind it would be a reason to use the standard syslog system built into

220
00:17:44,350 --> 00:17:50,220
Linux instead of for example creating your own logging service system from scratch.

221
00:17:50,720 --> 00:17:54,180
OK let's add this longer functionality to our script

222
00:18:00,440 --> 00:18:03,380
logger Dashti give it the name of our script.

223
00:18:06,850 --> 00:18:11,740
And then we'll send the message to the logfile.

224
00:18:11,870 --> 00:18:17,930
Now regardless of whether the message is displayed on standard out it will get recorded in the system

225
00:18:17,930 --> 00:18:18,260
log.

226
00:18:18,260 --> 00:18:19,590
So let's try it out here.

227
00:18:20,850 --> 00:18:24,420
When we execute our script our messages are displayed to the screen.

228
00:18:24,420 --> 00:18:27,020
Now let's see if they made it to the log file.

229
00:18:30,570 --> 00:18:36,660
And sure enough they have no it's turned verbose mode off and see what that's like.

230
00:18:36,950 --> 00:18:43,550
OK let's change this from true to false and execute our script.

231
00:18:43,630 --> 00:18:47,850
So there's no output to standard output there's nothing on our screen.

232
00:18:47,860 --> 00:18:51,580
Let's see if it made its way to the log file however

233
00:18:55,450 --> 00:19:00,230
Kay says hello and this is fun so let's do that again here and then.

234
00:19:00,310 --> 00:19:00,640
Yup.

235
00:19:00,700 --> 00:19:04,780
It keeps adding to the log file so that is working.

236
00:19:04,780 --> 00:19:07,900
Now let's go ahead and turn verbose mode back on

237
00:19:17,480 --> 00:19:19,490
before we write our next function.

238
00:19:19,490 --> 00:19:24,510
Let's add a quick comment to the top of this function explaining what it does.

239
00:19:24,530 --> 00:19:28,960
Now we do this for our scripts and so our functions are like little scripts within a script.

240
00:19:29,000 --> 00:19:31,760
So let's do that here to.

241
00:19:31,790 --> 00:19:33,540
So I'll go here and say

242
00:19:36,720 --> 00:19:47,250
this function sends a message to this log and to standard output if verbose is true.

243
00:19:47,600 --> 00:19:53,400
Hey if you wanted to add more information you can do that.

244
00:19:53,400 --> 00:19:58,680
Some people like to include things like any global variables that are used inside the function or by

245
00:19:58,680 --> 00:19:59,460
the function.

246
00:19:59,640 --> 00:20:04,470
Any arguments that the function accepts and anything the function might return.

247
00:20:04,470 --> 00:20:08,180
Now we haven't covered returns yet but we'll get to that soon enough.

248
00:20:08,190 --> 00:20:14,430
Moving on to our next to function as a reminder functions have to be defined before they are used.

249
00:20:14,460 --> 00:20:18,150
So a good practice is to put all your functions at the top of your script.

250
00:20:18,940 --> 00:20:24,790
The only things I would consider putting before the functions are constant global variables and sourcing

251
00:20:24,790 --> 00:20:29,630
script libraries again do not call a function before it's defined.

252
00:20:29,950 --> 00:20:35,230
Let's say you have a script that is going to update several files.

253
00:20:35,290 --> 00:20:39,090
You've lived a life long enough to know that sometimes things go wrong.

254
00:20:39,250 --> 00:20:43,650
So you want to make a backup of every single file before you modify it.

255
00:20:43,660 --> 00:20:46,760
Or more accurately before your script modifies it.

256
00:20:46,900 --> 00:20:52,720
That way if you have an error in your script or something unexpected happens you have a good copy of

257
00:20:52,720 --> 00:20:54,450
each file to go back to.

258
00:20:54,460 --> 00:20:58,710
So let's call this particular function back up underscore file

259
00:21:05,190 --> 00:21:06,320
only to come in here.

260
00:21:15,790 --> 00:21:19,670
All right we'll get to this return statement here in just a second.

261
00:21:19,700 --> 00:21:35,230
We're going to use a variable in our function so we'll make that local.

262
00:21:35,360 --> 00:21:38,620
We'll do a quick check to see if that file got passed and exists.

263
00:21:47,980 --> 00:21:52,000
Again we're setting a variable so we're going to use the local keyword here

264
00:22:09,840 --> 00:22:12,590
looks like I miss my clothing parentheses here.

265
00:22:12,590 --> 00:22:18,020
I mean do that.

266
00:22:18,140 --> 00:22:21,350
You're probably already familiar with the temp directory.

267
00:22:21,350 --> 00:22:28,220
However here I am using forward slash var forward slash temp because the files in var temp will survive

268
00:22:28,220 --> 00:22:33,200
a reboot while those in slash temp are not guaranteed to survive a reboot.

269
00:22:33,200 --> 00:22:39,970
Typically the files in temp are cleared on boot and are also cleared more often on a running system.

270
00:22:39,980 --> 00:22:45,560
I think the default for Scinto 7 is that files and temp are deleted every 10 days while the files in

271
00:22:45,560 --> 00:22:48,410
var temp are deleted every 30 days.

272
00:22:48,410 --> 00:22:53,870
That said I want to make sure that if I break a file and then do something like reboot the system that

273
00:22:53,870 --> 00:22:55,280
I don't lose that file.

274
00:22:55,280 --> 00:23:02,070
Hence the reason for me choosing the location of forward slash var Ford slash temp.

275
00:23:02,120 --> 00:23:04,400
All right continuing with our variable here.

276
00:23:04,400 --> 00:23:09,950
As you know the base name command removes the path to the file and just leaves us with a file name and

277
00:23:09,950 --> 00:23:15,440
we don't care about its original path because we just going to put a copy of it in var temp anyway.

278
00:23:15,440 --> 00:23:20,360
Also here we're using command substitution with the date command and you've used the date command with

279
00:23:20,360 --> 00:23:22,160
a couple of different formats before.

280
00:23:22,280 --> 00:23:28,790
But now I'm introducing the capital F format now capital F you can think of is standing for a full date

281
00:23:28,990 --> 00:23:33,080
and it displays the year month day using numbers.

282
00:23:33,080 --> 00:23:39,830
I love using this format because it makes sorting by date very easy once we call this function a couple

283
00:23:39,830 --> 00:23:42,010
times you'll see exactly what I mean.

284
00:23:42,020 --> 00:23:48,940
Also I attempted to account for multiple backups of the same file on the same day by appending the nanoseconds

285
00:23:48,950 --> 00:23:55,100
when the date command was called that's represented by the percent sign followed by capital N..

286
00:23:55,400 --> 00:24:00,830
We could have used a shell built in variable here to something like Dollar Sign random or dollar sign

287
00:24:00,830 --> 00:24:07,760
bash PID or even Dollar Sign Dollar Sign which expands to the PID or process id of the current running

288
00:24:07,760 --> 00:24:08,900
script.

289
00:24:08,900 --> 00:24:11,830
So now in this function let's call our other function here.

290
00:24:49,110 --> 00:24:53,880
So after we use the log function to record what we're going to do here or communicate our intentions

291
00:24:53,880 --> 00:24:58,180
here then we're going to use the C-p command to actually perform a copy.

292
00:24:58,200 --> 00:25:04,710
Now the dash option to the copy command is short for preserve and it preserves the files mode ownership

293
00:25:04,740 --> 00:25:06,230
and time stamps.

294
00:25:06,390 --> 00:25:12,110
If you don't use the dash option then the copy of the original file will have the current time stamp.

295
00:25:12,120 --> 00:25:17,790
I personally like to preserve the original time stamp on the copy just in case I need to put that copy

296
00:25:17,790 --> 00:25:20,370
back in place because it's a backup.

297
00:25:20,370 --> 00:25:25,890
The contents of that file haven't changed so in my opinion it makes sense to keep its time stamps the

298
00:25:25,890 --> 00:25:29,750
way they were instead of updating the time stamp to today.

299
00:25:29,910 --> 00:25:35,760
In the grand scheme of things this is really minor but it's just something to think about each function

300
00:25:35,760 --> 00:25:39,520
like each command returns an exit status by default.

301
00:25:39,570 --> 00:25:45,120
The function returns the exit status of the last command it executes in the case where the file that

302
00:25:45,120 --> 00:25:47,490
was passed to the function actually exists.

303
00:25:47,550 --> 00:25:54,090
We'll just let C-p return whatever exit status is appropriate and use that as the exit status for our

304
00:25:54,090 --> 00:25:55,110
function.

305
00:25:55,110 --> 00:26:01,410
If for some reason the CB command fails it will return a non-zero exit status and thus our backup file

306
00:26:01,410 --> 00:26:05,680
function will return that same non zero exit status.

307
00:26:24,330 --> 00:26:29,940
Here if the file doesn't exist that means we obviously can't make a copy of it a backup copy of it.

308
00:26:30,120 --> 00:26:44,190
So our function more or less fails and that's why we're going to return a non zero exit status.

309
00:26:44,190 --> 00:26:47,040
Now let's go ahead and call this function in our code here.

310
00:26:48,010 --> 00:26:59,390
A backup file let's back up the NC password file and lets see it in action.

311
00:26:59,490 --> 00:27:05,460
K we have the output displayed to our screen because we have verbose mode on and then we also see the

312
00:27:05,460 --> 00:27:11,820
output that was generated inside the backup file function which in turn call the log function to tell

313
00:27:11,820 --> 00:27:14,010
us about the backup that it made.

314
00:27:14,280 --> 00:27:18,580
So let's see if these are messages made it to the log file.

315
00:27:21,280 --> 00:27:22,410
Hey sure enough they have.

316
00:27:22,410 --> 00:27:28,290
Now we have a record of exactly what happened during that run of that script and exactly when it happened

317
00:27:28,620 --> 00:27:35,230
and all that good information there is a look at the file we copied here into var temp.

318
00:27:35,290 --> 00:27:40,620
You can see that the file that was in the log message here is this file here.

319
00:27:40,710 --> 00:27:45,690
Obviously I was playing around with this script yesterday doing some tests and so that's why we have

320
00:27:45,750 --> 00:27:48,320
these other password files there.

321
00:27:48,330 --> 00:27:56,400
Now let's look at ANSI password know and see what happens when we execute the copy command with out

322
00:27:56,430 --> 00:27:58,930
the dash options or do C.P ETSI.

323
00:27:59,100 --> 00:28:05,210
He is a W.D. and will copy that into var temp and we'll look at the contents of our temp.

324
00:28:05,220 --> 00:28:11,740
Now right now the date is January 12th and the date of that file is also January 12th.

325
00:28:11,860 --> 00:28:16,230
But if you look at its password it's really January 7th.

326
00:28:16,360 --> 00:28:18,850
It's the original time stamp on that file.

327
00:28:18,870 --> 00:28:22,000
So again that was the difference with the dash p option.

328
00:28:22,380 --> 00:28:24,080
OK we're getting really close to the end.

329
00:28:24,080 --> 00:28:25,750
Just one more little block of code.

330
00:28:25,820 --> 00:28:28,370
So let's jump back into our script.

331
00:28:28,680 --> 00:28:33,690
So as we discussed earlier a function has a return code or exit status just like any other command on

332
00:28:33,690 --> 00:28:34,690
a Linux system.

333
00:28:34,830 --> 00:28:52,970
Now let's check that status.

334
00:28:53,080 --> 00:28:56,560
So let's do it in the positive if the return code is zero.

335
00:28:56,560 --> 00:29:04,970
That means it's success so that we can do then is say hey the file backup succeeded.

336
00:29:05,150 --> 00:29:15,130
And then if it was not 0 then we'll say while backup failed and we'll exit the entire script there.

337
00:29:15,140 --> 00:29:20,480
So again if the backup function succeeds we're going to get that log file messages as file backup succeeded

338
00:29:20,480 --> 00:29:28,070
if it fails will log a file backup failed and exit the entire script itself with a non-zero exit status.

339
00:29:28,070 --> 00:29:34,730
Now by the way inside a function it's super important to use return and not exit if the exit command

340
00:29:34,730 --> 00:29:42,290
gets executed it exits the entire script no matter if that exit command is inside a function or not.

341
00:29:42,470 --> 00:29:43,280
So exit.

342
00:29:43,280 --> 00:29:46,040
Remember the exit is for the entire script.

343
00:29:46,070 --> 00:29:48,120
Return is just for the function.

344
00:29:48,120 --> 00:29:50,730
So now let's try this little extra code out

345
00:29:54,780 --> 00:29:56,820
right it looks like our backup succeeded.

346
00:29:56,820 --> 00:29:58,500
Let's look at the messages file.

347
00:30:00,960 --> 00:30:01,270
OK.

348
00:30:01,300 --> 00:30:08,140
Our file backup succeeded message ended up in the messages file to if we were to pass the backup file

349
00:30:08,140 --> 00:30:15,340
function in a file that didn't exist we would trigger an error or if the disk was full or if the file

350
00:30:15,340 --> 00:30:20,680
system was in a read only state when the backup was attempted it would also trigger an error state and

351
00:30:20,740 --> 00:30:22,210
exit the script.

352
00:30:22,300 --> 00:30:27,670
By the way this bit of code was just to show you that you can check the exit status of a function just

353
00:30:27,670 --> 00:30:29,870
like you can any other command.

354
00:30:29,890 --> 00:30:34,240
However in this particular case you would want to check if the backup succeeded or not every single

355
00:30:34,240 --> 00:30:35,710
time you performed a backup.

356
00:30:35,890 --> 00:30:42,070
And that means in practice you would most likely add this particular check or this bit of code inside

357
00:30:42,280 --> 00:30:44,490
the backup file function itself.

358
00:30:44,740 --> 00:30:49,990
If you wanted to over engineer this thing you could totally create three functions to do the same bit

359
00:30:49,990 --> 00:30:50,630
of work.

360
00:30:50,800 --> 00:30:52,510
One function would perform the backup.

361
00:30:52,510 --> 00:30:58,450
One would be use to check if the backup actually succeeded in a third function would be the one that

362
00:30:58,450 --> 00:31:03,250
you would actually call in your script which would in turn call the other two functions it would be

363
00:31:03,250 --> 00:31:08,820
like a wrapper around those functions and it would look something like this.

364
00:31:08,830 --> 00:31:15,770
So we'll just declare a function here backup file and let's say we call our other function that actually

365
00:31:15,770 --> 00:31:23,590
does the backup and we'll call it perform back up and we'll just pass that right along here.

366
00:31:25,970 --> 00:31:30,640
Then we want to check the backup.

367
00:31:30,690 --> 00:31:35,910
This is actually going to fail when I call it because those other functions don't exist right we just

368
00:31:35,910 --> 00:31:41,930
kind of made this up on the fly so I'll do this backup file and see password for example.

369
00:31:42,030 --> 00:31:46,500
And sure enough when we call it it executes to perform backup but that command isn't found because again

370
00:31:46,500 --> 00:31:47,470
it doesn't exist.

371
00:31:47,580 --> 00:31:50,760
And then it calls check back up again it doesn't exist.

372
00:31:50,760 --> 00:31:56,690
So anyway as you might have noticed you can define a function at the command line like I did right here

373
00:31:57,000 --> 00:31:59,410
and you really already know this spinel right.

374
00:31:59,550 --> 00:32:04,060
A shell script is just automating what you can do at the command line anyway.

375
00:32:04,320 --> 00:32:08,450
So let's let's look at this type mâché back up on score file.

376
00:32:08,460 --> 00:32:14,550
It tells us it has a function and it displays the code that is contained in that function or that function

377
00:32:14,550 --> 00:32:15,530
definition.

378
00:32:15,540 --> 00:32:20,830
This way you can write functions and have them write inside your current running shell.

379
00:32:20,850 --> 00:32:24,540
I feel like we've covered a lot about functions don't you.

380
00:32:24,540 --> 00:32:31,370
Before we wrap this up let's do a little refresher of the main points about working with functions in

381
00:32:31,380 --> 00:32:37,010
this lesson you learned about the concept of dry which stands for don't repeat yourself.

382
00:32:37,080 --> 00:32:41,880
If you find yourself writing the same bit of code in multiple places in your script it's a good sign

383
00:32:41,880 --> 00:32:43,780
that you should use a function.

384
00:32:43,890 --> 00:32:49,680
You also learned that by default all variables are global in scope and you learn how to use the local

385
00:32:49,680 --> 00:32:55,110
keyword to define local variables that are only available within the function that they are defined

386
00:32:55,110 --> 00:32:56,140
in.

387
00:32:56,160 --> 00:32:59,590
You also learned how to use positional parameters within your functions.

388
00:32:59,790 --> 00:33:06,060
And finally we covered how to use EXIT statuses with your functions by using the return command.
