Tag Archives | bash scripts

Bash Scripting Part6 – Create and Use Bash Functions

Before we talk about bash functions, let’s discuss this situation. When writing bash scripts, you’ll find yourself that you are using the same code in multiple places. If you get tired of writing the same lines of code again and again in your bash script, it would be nice to write the block of code once and call it anywhere in your bash script. The bash shell allows you to do just that with Functions. Bash functions are blocks of code that you can reuse them anywhere in your code. Anytime you want to use this block of code in your script, you simply type the function name given to it. We are going to talk about how to create your own bash functions and how to use them in shell scripts.

Continue Reading →

Creating a function

You can define a function like this:

functionName() {

}

The brackets () is required to define the function.

Also, you can define the function using the function keyword, but this keyword is deprecated for POSIX portability.

function functionName() {

# Deprecated definition but still used and working

}

In the second definition, the brackets are not required.

Using Functions

#!/bin/bash

myfunc() {

echo "Using functions"

}

total=1

while [ $total -le 3 ]; do

myfunc

total=$(($total + 1))

done

echo "Loop finished"

myfunc

echo "End of the script"

Here we’ve created a function called myfunc and in order to call it, we just typed its name.

bash functions

The function can be called many times as you want.

Notice: If you try to use a function which is not defined, what will happen?

#!/bin/bash

total=1

while [ $total -le 3 ]; do

myfunc

total=$(($total + 1))

done

echo "Loop End"

myfunc() {

echo "Using function ..."

}

echo "End of the script"

call before declare

Oh, it’s an error because there no such function.

Another notice: bash function name must be unique. Otherwise, the new function will cancel the old function without any errors.

#!/bin/bash

myfunc() {

echo "The first function definition"

}

myfunc

function myfunc() {

echo "The second function definition"

}

myfunc

echo "End of the script"

override definition

As you can see, the second function definition takes control from the first one without any error so take care when defining functions.

Using the return Command

The return command returns an integer from the function.

There are two ways of using the return command; the first way is like this:

#!/bin/bash

myfunc() {

read -p "Enter a value: " value

echo "adding value"

return $(($value + 10))

}

myfunc

echo "The new value is $?"

return command

The myfunc function adds 10 to the  $value variable then show the sum using the $? Variable.

Don’t execute any commands before getting the value of the function, because the variable $? returns the status of the last line.

This return method returns integers. what about returning strings?

Using Function Output

The second way of returning a value from a bash function is command substitution. This way, you can return anything from the function.

#!/bin/bash

myfunc() {

read -p "Enter a value: " value

echo $(($value + 10))

}

result=$(myfunc)

echo "The value is $result"

bash functions output

Passing Parameters

We can deal with bash functions like small snippets that can be reused and that’s OK, but we need to make the function like an engine, we give it something and it returns a result based on what we provide.

You can use the environment variables to process the passed parameters to the function. The function name is declared as $0 variable, and the passed parameters are $1, $2, $3, etc.

You can get the number of passed parameters to the function using the ($#) variable.

We pass parameters like this:

myfunc $val1 10 20

The following example shows how to use the ($#) variable:

#!/bin/bash

addnum() {

if [ $# -gt 2 ]; then

echo "Incorrect parameters passed" # If parameters no equal 2

else

echo $(($1 + $2)) # Otherwise add them

fi

}

echo -n "Adding 10 and 15: "

value=$(addnum 10 15)

echo $value

echo -n "Adding three numbers: "

value=$(addnum 10 15 20)

echo $value

pass parameters

The addnum function gets the passed parameters count. If greater than 2 passed, it returns -1.

If there’s one parameter, the addnum function adds this parameter twice. If 2 parameters passed, the addnum function adds them together, and if you try to add three parameters it will return -1.

If you try to use the passed parameters inside the function, it fails:

#!/bin/bash

myfunc() {

echo $(($1 + $2 + $3 + $4))

}

if [ $# -eq 4 ]; then

value=$(myfunc)

echo "Total= $value"

else

echo "Passed parameters like this: myfunc a b c d"

fi

unknown parameters

Instead, you have to send them to the function like this:

#!/bin/bash

myfunc() {

echo $(($1 + $2 + $3 + $4))

}

if [ $# -eq 4 ]; then

value=$(myfunc $1 $2 $3 $4)

echo "Total= $value"

else

echo "Passed parameters like this: myfunc a b c d"

fi

bash functions parameters

Now it works!!

Processing Variables in Bash Functions

Every variable we use has a scope, the scope is variable visibility to your script.

You can define two types of variables:

  • Global
  • Local

Global Variables

They are visible and valid anywhere in the bash script. You can even get its value from inside the function.

If you declare a global variable within a function, you can get its value from outside the function.

Any variable you declare is a global variable by default. If you define a variable outside the function, you call it inside the function without problems:

#!/bin/bash

myfunc() {

input=$(($input + 10))

}

read -p "Enter a number: " input

myfunc

echo "The new value is: $input"

global variables

If you change the variable value inside the function, the value will be changed outside of the function.

So how to overcome something like this? Use local variables.

Local Variables

If you will use the variable inside the function only, you can declare it as a local variable using the local keyword  like this:

local tmp=$(( $val + 10 ))

So if you have two variables, one inside the function and the other is outside the function and they have the identical name, they won’t affect each other.

#!/bin/bash

myfunc() {

local tmp=$(($val + 10))

echo "The Temp from inside function is $tmp"

}

tmp=4

myfunc

echo "The temp from outside is $tmp"

local variables

When you use the $tmp variable inside the myfunc function, it doesn’t change the value of the $tmp which is outside the function.

Passing Arrays As Parameters

What will happen if you pass an array as a parameter to a function:

#!/bin/bash

myfunc() {

echo "The parameters are: $@"

arr=$1

echo "The received array is ${arr[*]}"

}

my_arr=(5 10 15)

echo "The old array is: ${my_arr[*]}"

myfunc ${my_arr[*]}

pass arrays

The function only takes the first value of the array variable.

You should disassemble the array into its single values, then use these values as function parameters. Finally, pack them into an array in the function like this:

#!/bin/bash

myfunc() {

local new_arr

new_arr=("$@")

echo "Updated value is: ${new_arr[*]}"

}

my_arr=(4 5 6)

echo "Old array is ${my_arr[*]}"

myfunc ${my_arr[*]}

pass arrays solution

The array variable was rebuilt thanks to the function.

Recursive Function

This feature enables the function to call itself from within the function itself.

The classic example of a recursive function is calculating factorials. To calculate the factorial of 3, use the following equation:

3! = 1 * 2 * 3

Instead, we can use the recursive function like this:

x! = x * (x-1)!

So to write the factorial function using bash scripting, it will be like this:

#!/bin/bash

fac_func() {

if [ $1 -eq 1 ]; then

echo 1

else

local tmp=$(($1 - 1))

local res=$(fac_func $tmp)

echo $(($res * $1))

fi

}

read -p "Enter value: " val

res=$(fac_func $val)

echo "The factorial of $val is: $res"

bash recursive function

Using recursive bash functions is so easy!

Creating Libraries

Now we know how to write functions and how to call them, but what if you want to use these bash functions or blocks of code on different bash script files without copying and pasting it on your files.

You can create a library for your functions and point to that library from any file as you need.

By using the source command, you can embed the library file script inside your shell script.

The source command has an alias which is the dot. To source a file in a shell script, write the following line:

. ./myscript

Let’s assume that we have a file called myfuncs that contains the following:

addnum() {

echo $(($1 + $2 + $3 + $4))

}

Now, we will use it in another bash script file like this:

#!/bin/bash

. ./myfuncs

result=$(addnum 10 10 5 5)

echo "Total = $result"

source command

Awesome!! We’ve used the bash functions inside our bash script file, we can also use them in our shell directly.

Use Bash Functions From Command Line

Well, that is easy, if you read the previous post which was about the signals and jobs you will have an idea about how to source our functions file in the bashrc file and hence we can use the functions directly from the bash shell. Cool

Edit the bashrc file at /home/username and add this line:

. /home/likegeeks/Desktop/myfuncs

Make sure you type the correct path.

Now the function is available for us to use in the command line directly:

addnum 10 20

use from shell

Note: you may need to log out and log in to use the bash functions from the shell.

Another note: if you make your function name like any of the built-in commands you will overwrite the default command so you should take care of that.

I hope you like the post. Keep coming back.

Thank you.

0

Linux Bash Scripting Part5 – Signals and Jobs

In the previous post, we talked about input, output, and redirection in bash scripts. Today we will learn how to run and control them on a Linux system. Till now, we can run scripts only from the command line interface. This isn’t the only way to run Linux bash scripts. This post describes the different ways to control your Linux bash scripts. In shell scripts, we talked about important things called Input, Output and Redirection. Everything is a file in Linux and that includes input and output. So we need to understand each one in detail.

 

Continue Reading →

Your Linux bash scripts don’t control these signals, you can program your bash script to recognize signals and perform commands based on the signal that was sent.

Stop a Process

To stop a running process, you can press Ctrl+C which generates SIGINT signal to stop the current process running in the shell.

sleep 100

Ctrl+C

Linux bash scripting Signals and Jobs stop process

Pause a Process

The Ctrl+Z keys generate a SIGTSTP signal to stop any processes running in the shell, and that leaves the program in memory.

sleep 100

Ctrl+Z

pause process

The number between brackets which is (1) is the job number.

If try to exit the shell and you have a stopped job assigned to your shell, the bash warns you if you.

The ps command is used to view the stopped jobs.

ps –l

ps -l

In the S column (process state), it shows the traced (T) or stopped (S) states.

If you want to terminate a stopped job you can kill its process by using kill command.

kill processID

Trap Signals

To trap signals, you can use the trap command. If the script gets a signal defined by the trap command, it stops processing and instead the script handles the signal.

You can trap signals using the trap command like this:

#!/bin/bash

trap "echo 'Ctrl-C was trapped'" SIGINT

total=1

while [ $total -le 3 ]; do

echo "#$total"

sleep 2

total=$(($total + 1))

done

Every time you press Ctrl+C, the signal is trapped and the message is printed.

trap signal

If you press Ctrl+C, the echo statement specified in the trap command is printed instead of stopping the script. Cool, right?

Trapping The Script Exit

You can trap the shell script exit using the trap command like this:

#!/bin/bash

# Add the EXIT signal to trap it

trap "echo Goodbye..." EXIT

total=1

while [ $total -le 3 ]; do

echo "#$total"

sleep 2

total=$(($total + 1))

done

trap exit

When the bash script exits, the Goodbye message is printed as expected.

Also, if you exit the script before finishing its work, the EXIT trap will be fired.

Modifying Or Removing a Trap

You can reissue the trap command with new options like this:

#!/bin/bash

trap "echo 'Ctrl-C is trapped.'" SIGINT

total=1

while [ $total -le 3 ]; do

echo "Loop #$total"

sleep 2

total=$(($total + 1))

done

# Trap the SIGINT

trap "echo ' The trap changed'" SIGINT

total=1

while [ $total -le 3 ]; do

echo "Second Loop #$total"

sleep 1

total=$(($total + 1))

done

modify trap

Notice how the script manages the signal after changing the signal trap.

You can also remove a trap by using 2 dashes trap -- SIGNAL

#!/bin/bash

trap "echo 'Ctrl-C is trapped.'" SIGINT

total=1

while [ $total -le 3 ]; do

echo "#$total"

sleep 1

total=$(($total + 1))

done

trap -- SIGINT

echo "I just removed the trap"

total=1

while [ $total -le 3 ]; do

echo "Loop #2 #$total"

sleep 2

total=$(($total + 1))

done

Notice how the script processes the signal before removing the trap and after removing the trap.

./myscript

Crtl+C

remove trap

The first Ctrl+C was trapped and the script continues running while the second one exits the script because the trap was removed.

Running Linux Bash Scripts in Background Mode

If you see the output of the ps command, you will see all the running processes in the background and not tied to the terminal.

We can do the same, just place ampersand symbol (&) after the command.

#!/bin/bash

total=1

while [ $total -le 3 ]; do

sleep 2

total=$(($total + 1))

done

./myscipt &

run in background

Once you’ve done that, the script runs in a separate background process on the system and you can see the process id between the square brackets.

When the script dies,  you will see a message on the terminal.

Notice that while the background process is running, you can use your terminal monitor for STDOUT and STDERR messages so if an error occurs, you will see the error message and normal output.

run script in background

The background process will exit if you exit your terminal session.

So what if you want to continue running even if you close the terminal?

Running Scripts without a Hang-Up

You can run your Linux bash scripts in the background process even if you exit the terminal session using the nohup command.

The nohup command blocks any SIGHUP signals. This blocks the process from exiting when you exit your terminal.

nohup ./myscript &

linux bash nohup command

After running the nohup command, you can’t see any output or error from your script. The output and error messages are sent to a file called nohup.out.

Note: when running multiple commands from the same directory will override the nohup.out file content.

Viewing Jobs

To view the current jobs, you can use the jobs command.

#!/bin/bash

total=1

while [ $total -le 3 ]; do

echo "#$count"

sleep 5

total=$(($total + 1))

done

Then run it.

./myscript

Then press Ctrl+Z to stop the script.

linux bash view jobs

Run the same bash script but in the background using the ampersand symbol and redirect the output to a file just for clarification.

./myscript > outfile &

linux bash list jobs

The jobs command shows the stopped and the running jobs.

jobs –l

-l parameter to view the process ID

 Restarting Stopped Jobs

The bg command is used to restart a job in background mode.

./myscript

Then press Ctrl+Z

Now it is stopped.

bg

linux bash restart job

After using bg command, it is now running in background mode.

If you have multiple stopped jobs, you can do the same by specifying the job number to the bg command.

The fg command is used to restart a job in foreground mode.

fg 1

Scheduling a Job

The Linux system provides 2 ways to run a bash script at a predefined time:

  • at command.
  • cron table.

The at command

This is the format of the command

at [-f filename] time

The at command can accept different time formats:

  • Standard time format like 10:15.
  • An AM/PM indicator like 11:15PM.
  • A specifically named time like now, midnight.

You can include a specific date, using some different date formats:

  • A standard date format, such as MMDDYY or DD.MM.YY.
  • A text date, such as June 10 or Feb 12, with or without the year.
  • Now + 25 minutes.
  • 05:15AM tomorrow.
  • 11:15 + 7 days.

We don’t want to dig deep into the at command, but for now, just make it simple.

at -f ./myscript now

linux bash at command

The -M parameter is used to send the output to email if the system has email, and if not, this will suppress the output of the at command.

To list the pending jobs, use atq command:

linux bash at queue

Remove Pending Jobs

To remove a pending job, use the atrm command:

atrm 18

delete at queue

You must specify the job number to the atrm command.

Scheduling Scripts

What if you need to run a script at the same time every day or every month or so?

You can use the crontab command to schedule jobs.

To list the scheduled jobs, use the -l parameter:

crontab –l

The format for crontab is:

minute,Hour, dayofmonth, month, and dayofweek

So if you want to run a command daily at 10:30, type the following:

30 10 * * * command

The wildcard character (*) used to indicate that the cron will execute the command daily on every month at 10:30.

To run a command at 5:30 PM every Tuesday, you would use the following:

30 17 * * 2 command

The day of the week starts from 0 to 6 where Sunday=0 and Saturday=6.

To run a command at 10:00 on the beginning of every month:

00 10 1 * * command

The day of the month is from 1 to 31.

Let’s keep it simple for now and we will discuss the cron in great detail in future posts.

To edit the cron table, use the -e parameter like this:

crontab –e

Then type your command like the following:

30 10 * * * /home/likegeeks/Desktop/myscript

This will schedule our script to run at 10:30 every day.

Note: sometimes you see error says Resource temporarily unavailable.

All you have to do is this:

rm -f /var/run/crond.pid

You should be a root user to do this.

Just that simple!

You can use one of the pre-configured cron script directories like:

/etc/cron.hourly

/etc/cron.daily

/etc/cron.weekly

/etc/cron.monthly

Just put your bash script file on any of these directories and it will run periodically.

Starting Scripts at Login

In the previous posts, we’ve talked about startup files, I recommend you to review the previous.

$HOME/.bash_profile

$HOME/.bash_login

$HOME/.profile

To run your scripts at login, place your code in $HOME/.bash_profile.

Starting Scripts When Opening the Shell

OK, what about running our bash script when the shell opens? Easy.

Type your script on .bashrc file.

And now if you open the shell window, it will execute that command.

I hope you find the post useful. keep coming back.

Thank you.

0

Bash Scripting Part6 – Create and Use Bash Functions

Before we talk about bash functions, let’s discuss this situation. When writing bash scripts, you’ll find yourself that you are using the same code in multiple places. If you get tired of writing the same lines of code again and again in your bash script, it would be nice to write the block of code once and call it anywhere in your bash script. The bash shell allows you to do just that with Functions. Bash functions are blocks of code that you can reuse them anywhere in your code. Anytime you want to use this block of code in your script, you simply type the function name given to it. We are going to talk about how to create your own bash functions and how to use them in shell scripts.

Continue Reading →

Creating a function

You can create a function like this:

functionName {

}

Or like this:

functionName() {

}

The parenthesis on the second snippet is used to pass values to the function from outside of it, so these values can be used inside the function.

Using Functions

#!/bin/bash

function myfunc {

echo "Using functions"

}

total=1

while [ $total -le 3 ]

do

myfunc

total=$(( $total + 1 ))

done

echo "Loop finished"

myfunc

echo "End of the script"

Here we’ve created a function called myfunc and in order to call it, we just typed its name.

bash functions

The function can be called many times as you want.

Notice: If you try to use a function which is not defined, what will happen?

#!/bin/bash

total=1

while [ $total -le 3 ]

do

myfunc

total=$(( $total + 1 ))

done

echo "Loop End"

function myfunc {

echo "Using function ..."

}

echo "End of the script"

bash functions call before declare

Oh, it’s an error because there no such function.

Another notice: bash function name must be unique. Otherwise, the new function will cancel the old function without any errors.

#!/bin/bash

function myfunc {

echo "The first function definition"

}

myfunc

function myfunc {

echo "The second function definition"

}

myfunc

echo "End of the script"

bash functions override definition

As you can see, the second function definition takes control from the first one without any error so take care when defining functions.

Using the return Command

The return command returns an integer from the function.

There are two ways of using return command; the first way is like this:

#!/bin/bash

function myfunc {

read -p "Enter a value: " value

echo "adding value"

return $(( $value + 10 ))

}

myfunc

echo "The new value is $?"

bash functions return command

The myfunc function adds 10 to the  $value variable then show the sum using the $? Variable.

Don’t execute any commands before getting the value of the function, because the variable $? returns the status of the last line.

This return method returns integers. what about returning strings?

Using Function Output

The second way of returning a value from a bash function is command substitution. This way, you can return anything from the function.

#!/bin/bash

function myfunc {

read -p "Enter a value: " value

echo $(( $value + 10 ))

}

result=$( myfunc)

echo "The value is $result"

bash functions output

Passing Parameters

We can deal with bash functions like small snippets that can be reused and that’s OK, but we need to make the function like an engine, we give it something and it returns a result based on what we provide.

You can use the environment variables to process the passed parameters to the function. The function name is declared as $0 variable, and the passed parameters are $1, $2, $3, etc.

You can get the number of passed parameters to the function using the ($#) variable.

We pass parameters like this:

myfunc $val1 10 20

The following example shows how to use the ($#) variable:

#!/bin/bash

function addnum {

if [ $# -gt 2 ]

then

# If parameters no equal 2

echo "Incorrect parameters passed"

else

# Otherwise add them

echo $(( $1 + $2 ))

fi

}

echo -n "Adding 10 and 15: "

value=$(addnum 10 15)

echo $value

echo -n "Adding three numbers: "

value=$(addnum 10 15 20)

echo $value

bash functions pass parameters

The addnum function gets the passed parameters count. If greater than 2 passed, it returns -1.

If there’s one parameter, the addnum function adds this parameter twice. If 2 parameters passed, the addnum function adds them together, and if you try to add three parameters it will return -1.

If you try to use the passed parameters inside the function, it fails:

#!/bin/bash

function myfunc {

echo $(( $1 + $2 + $3 + $4))

}

if [ $# -eq 4 ]

then

value=$( myfunc)

echo "Total= $value"

else

echo "Passed parameters like this: myfunc a b c d"

fi

bash functions unknown parameters

Instead, you have to send them to the function like this:

#!/bin/bash

function myfunc {

echo $(( $1 + $2 + $3 + $4))

}

if [ $# -eq 4 ]

then

value=$(myfunc $1 $2 $3 $4)

echo "Total= $value"

else

echo "Passed parameters like this: myfunc a b c d"

fi

bash functions parameters

Now it works!!

Processing Variables in Bash Functions

Every variable we use has a scope, the scope is variable visibility to your script.

You can define two types of variables:

  • Global
  • Local

Global Variables

They are visible and valid anywhere in the bash script. You can even get its value from inside the function.

If you declare a global variable within a function, you can get its value from outside the function.

Any variable you declare is a global variable by default. If you define a variable outside the function, you call it inside the function without problems:

#!/bin/bash

function myfunc {

input=$(( $input + 10 ))

}

read -p "Enter a number: " input

myfunc

echo "The new value is: $input"

bash functions global variables

If you change the variable value inside the function, the value will be changed outside of the function.

So how to overcome something like this? Use local variables.

Local Variables

If you will use the variable inside the function only, you can declare it as a local variable using the local keyword  like this:

local tmp=$(( $val + 10 ))

So if you have two variables, one inside the function and the other is outside the function and they have the identical name, they won’t affect each other.

#!/bin/bash

function myfunc {

local tmp=$[ $val + 10 ]

echo "The Temp from inside function is $tmp"

}

tmp=4

myfunc

echo "The temp from outside is $tmp"

bash functions local variables

When you use the $tmp variable inside the myfunc function, it doesn’t change the value of the $tmp which is outside the function.

Passing Arrays As Parameters

What will happen if you pass an array as a parameter to a function:

#!/bin/bash

function myfunc {

echo "The parameters are: $@"

arr=$1

echo "The received array is ${arr[*]}"

}

my_arr=(5 10 15)

echo "The old array is: ${my_arr[*]}"

myfunc $my_arr

bash functions pass arrays

The function only takes the first value of the array variable.

You should disassemble the array into its single values, then use these values as function parameters. Finally, pack them into an array in the function like this:

#!/bin/bash

function myfunc {

local new_arr

new_arr=("$@")

echo "Updated value is: ${new_arr[*]}"

}

my_arr=(4 5 6)

echo "Old array is ${my_arr[*]}"

myfunc ${my_arr[*]}

bash functions pass arrays solution

The array variable was rebuilt thanks to the function.

Recursive Function

This feature enables the function to call itself from within the function itself.

The classic example of a recursive function is calculating factorials. To calculate the factorial of 3, use the following equation:

3! = 1 * 2 * 3

Instead, we can use the recursive function like this:

x! = x * (x-1)!

So to write the factorial function using bash scripting, it will be like this:

#!/bin/bash

function fac_func {

if [ $1 -eq 1 ]

then

echo 1

else

local tmp=$(( $1 - 1 ))

local res=$(fac_func $tmp)

echo $(( $res * $1 ))

fi

}

read -p "Enter value: " val

res=$(fac_func $val)

echo "The factorial of $val is: $res"

bash recursive function

Using recursive bash functions is so easy!

Creating Libraries

Now we know how to write functions and how to call them, but what if you want to use these bash functions or blocks of code on different bash script files without copying and pasting it on your files.

You can create a library for your functions and point to that library from any file as you need.

By using the source command, you can embed the library file script inside your shell script.

The source command has an alias which is the dot. To source a file in a shell script, write the following line:

. ./myscript

Let’s assume that we have a file called myfuncs that contains the following:

function addnum {

echo $(( $1 + $2 + $3 + $4))

}

Now, we will use it in another bash script file like this:

#!/bin/bash

. ./myfuncs

result=$(addnum 10 10 5 5)

echo "Total = $result"

bash functions source command

Awesome!! We’ve used the bash functions inside our bash script file, we can also use them in our shell directly.

Use Bash Functions From Command Line

Well, that is easy, if you read the previous post which was about the signals and jobs you will have an idea about how to source our functions file in the .bashrc file and hence we can use the functions directly from the bash shell. Cool

Edit the .bashrc file and add this line:

. /home/likegeeks/Desktop/myfuncs

Make sure you type the correct path.

Now the function is available for us to use in the command line directly:

$ addnum 10 20

bash functions use from shell

Note: you may need to logout and login to use the bash functions from the shell.

Another note: if you make your function name like any of the built-in commands you will overwrite the default command so you should take care of that.

I hope you like the post. Keep coming back.

Thank you.

likegeeks.com

0