• No results found

Bash Guide

N/A
N/A
Protected

Academic year: 2021

Share "Bash Guide"

Copied!
184
0
0

Loading.... (view fulltext now)

Full text

(1)

LINUX

Bash Script Step By Step,

You Will Love It

February 7, 2017 admin 3 Comments

Today we are going to talk about bash script or shell scripting actually, they are called

shell scripts in general but we are going to

call them bash scripts because we are going to use bash among the other Linux shells. There

Search …

SEARCH

(2)

Bash shebang Setting permission Print messages using variables Environment variables User variables Command substitution Math calculation if-then statement

Nested if- Statement

Numeric Comparisons

String Comparisons

(3)

The key to bash script is the ability to enter multiple Commands and deal with the results from each command, even possibly passing the results of one command to another. The shell allows you to run multiple commands in a single step.

If you want to run two commands together or more, you can type them on the same line, separated with a semicolon

Actually what you have typed is a bash script!!

This simple script uses just two bash shell commands.

The pwd command runs first, displaying the current working directory followed by the

output of the whoami command, showing who is currently logged in user.

Using this technique, you can string together as many commands as you wish, maximum

(4)

Well, that’s fine but it has a problem that you must enter the command at the command prompt every time you want to run it ok, what about we combine the commands into a file. And when we need to run those commands we run that file only. This is called the bash script

Now create an empty file using touch command as we discussed that in a previous post about

Linux commands. The first line we should define which shell we will use as we know there are many shells on Linux bash is one of them

Bash Script Shebang

Here we will write bash script and in order to do that we will type

In a normal bash script line, the pound sign (#) is used as a comment line which is not

processed by the shell. However, the first line

(5)

And the shell commands are entered one per line followed by enter and you can write a comment by adding the pound sign at the beginning of the file like this

You can use the semicolon and put multiple commands on the same

Line if you want to, but in bash script, you can list commands on separate lines, and this to make it simpler to read them later. The shell will process them any way.

Set Script Permission

Save the file, you are almost finished. All you need to do now is to set that file to be

executable in order to be able to run it

#!/bin/bash

# This is a comment pwd

(6)

Then try run it by just type it in the shell

And Yes it is executed

Print Messages

As we know from other posts, printing text is done by echo command

So take your knowledge to bash script and apply it

Now we edit our file and type this

chmod +x ./myscript

./myscript

(7)

Look at the output

Perfect! Now we can run commands and display text using echo command

If you don’t know echo command or how to edit a file I recommend you to view previous articles about basic Linux commands

Using Variables

Variables allow you to store information in the bash script for use with other commands in the script.

Running individual commands from the bash script is good, but this has its limitations.

There are two types of variables you can use in your bash script

(8)

in your shell commands to process information. You can do this by using environment variables.

We talked about environment variables on another post you can check it.

Notice that we were able to place the $HOME system variable in the double quotation marks in the first string, and the shell script still know it

What if we want to print the dollar sign itself?

The script sees a dollar sign within quotes; it

echo "I have $1 in my pocket"

#!/bin/bash

# display user home

(9)

By using escape characters back slash \ before the dollar sign like this

Now the bash script will print the dollar sign as it is

User variables

In addition to the environment variables, a bash script allows you to set and use your own

variables in the script.

Variables defined in the shell script maintain their values till bash script execution finished.

Like system variables, user variables can be referenced using the dollar sign

echo "I have \$1 in my pocket"

#!/bin/bash

(10)

Command substitution

One of the best features of bash scripts is the ability to extract information from the output of a command and assign it to a variable so you can use that value anywhere in your script

There are two ways to do that

The backtick character ` The $() format

Make sure when you type backtick character it is not the single quotation mark.

You must surround the entire command line command with two backtick characters like this

mydir=`pwd`

chmod +x myscript

(11)

The output of the command will be stored in that variable called mydir.

Math calculation

You can perform basic math calculations using $[] format

Just that easy

#!/bin/bash mydir=$(pwd) echo $mydir #!/bin/bash var1=$(( 5 + 5 )) echo $var1 var2=$(( $var1 * 2 )) echo $var2

(12)

Bash script requires some sort of logic flow control between the commands in the script. Like if the value is greater than 5 do that else do whatever you can imagine any login you want.

The most basic structure of if-then statement is like this

if command

then

commands

and here is an example

#!/bin/bash if pwd

then

echo "It works"

(13)

May be searching for a specific user in the users /etc/passwd and if it exists it prints that the user is present

We use grep command to search for the user in /etc/passwd file. You can check our tutorial

about basic Linux commands if you don’t know grep command.

If the user exists the bash script will print the message.

#!/bin/bash

user=likegeeks

if grep $user /etc/passwd

then

echo "The user $user Exists"

(14)

if-then-else Statement

The if-then-else statement looks like this

if command then commands else commands

if the first command runs and returns with a zero which means success it will not hit the commands after the else statement, otherwise, if the if statement returns non-zero which

means the statement condition not correct, At this case the shell will hit the commands after else statement.

#!/bin/bash

(15)

We are doing good till now, keep moving

Now, what if we have more else statements, like if user correct print this else if it is some other print this else print another thing?

Well that is easy also we can achieve by nesting if statements like this

if command1 then commands elif command2 then commands

echo "The user $user doesn’t exist"

(16)

commands after it else if none of those return zero it will execute the last commands only.

You can imagine any scenario here may be if the user doesn’t exist create it using the useradd command or do anything else.

Numeric Comparisons

You can perform numeric comparison between two numeric values using numeric comparison checks as on this list

n1 -eq n2 Checks if n1 is equal to n2

#!/bin/bash

user=anotherUser

if grep $user /etc/passwd

then

echo "The user $user Exists"

elif ls /home

echo "The user doesn’t exist but anyway there is a direc

(17)

n1 -le n2 Checks if n1 is less than or equal to n2

n1 -lt n2 Checks if n1 is less than n2

n1 -ne n2 Checks if n1 is not equal to n2

As an example, we will try one of them and the rest is the same

Note that the comparison statement is in square brackets as shown.

The val1 is greater than 5 so it will run the first

#!/bin/bash

val1=6

if [ $val1 -gt 5 ]

then

echo "The test value $value1 is greater than 5"

else

echo "The test value $value1 is not greater than 5"

(18)

The comparison functions you can use to evaluate two string values are

str1 = str2 Checks if str1 is the same as string str2

str1 != str2 Checks if str1 is not the same as str2

str1 < str2 Checks if str1 is less than str2

str1 > str2 Checks if str1 is greater than str2

-n str1 Checks if str1 has a length greater than zero

-z str1 Checks if str1 has a length of zero

We can apply string comparison on our example

#!/bin/bash

user ="likegeeks"

if [$user = $USER]

(19)

One tricky note about the greater than and

less than for string comparisons MUST be escaped with the back slash because by just

using the greater-than symbol itself in the script, no errors are generated, but the results are wrong. The script interpreted the

greater-than symbol as an output redirection. So you should do it like that

#!/bin/bash

val1=text

val2="another text"

if [ $val1 \> "$val2" ]

then

echo "$val1 is greater than $val2"

else

echo "$val1 is less than $val2"

(20)

Just little fix is to wrap the $vals with double quotation,  forcing it to stay as one string like this

Last tricky note about greater than and less

than for string comparisons is when working

with uppercase and lowercase letters. The

sort command handles uppercase letters opposite to the way the test conditions

consider them

#!/bin/bash

val1=text

val2="another text"

if [ $val1 \> "$val2" ]

then

echo "$val1 is greater than $val2"

else

echo "$val1 is less than $val2"

(21)

likegeeks

Likegeeks

Capitalized letters are treated as less than

lowercase letters in test comparisons. However, the sort command does exactly the opposite.

String test comparisons use standard ASCII

sort myfile

then

echo "$val1 is greater than $val2"

else

echo "$val1 is less than $val2"

(22)

defined for the system locale language settings.

File Comparisons

This is the best and most powerful and most used comparison in bash scripting there are many file comparisons that you can do in bash script

-d file Checks if file exists and is a directory

-e file Checks if file exists

-f file Checks if file exists and is a file

-r file Checks if file exists and is readable

-s file Checks if file exists and is not empty

-w file Checks if file exists and is writable

-x file Checks if file exists and is executable

(23)

-G file Checks if file exists and the default group is the same as the current user

As they imply, you will never forget them.

Let’s pick one of them and take it as an example

#!/bin/bash

mydir=/home/likegeeks

if [ -d $mydir ]

then

echo "The $mydir directory exists"

cd $ mydir

ls else

echo "The $mydir directory does not exist"

(24)

There are some other advanced if-then features but let’s make it on another post.

That’s for now. I hope you enjoy it and keep practicing more and more.

Wait for another tutorial about bash scripting so stay tuned.

LINUX

Bash Scripting The

Awesome Guide Part2

February 9, 2017 admin 4 Comments

(25)

demonstrates for loop, while in bash scripts

we will discuss the following:

for command

Iterating over simple values

Iterating over complex values

Reading values from a command

The field separator

Iterating over directory files

for Command C-Style

The while Command

Nesting Loops

Looping on File Data

Controlling the Loop

(26)

for Command

The bash shell provides the for command to allow you to create a loop that iterates through a series of values. This is the basic format of the bash shell for command

for var in list

do

commands

done

In each iteration, the variable var contains the current value in the list. The first iteration uses the first item in the list; the second iteration contains the second item, and so on until the end of the list items

Iterating over simple

values

(27)

As you can see from the output the $var

variable is changed on every loop cycle till the last item on the list.

Notice that the $var variable retained its value and allowed us to change the value and use it outside of the for command loop, like any variable.

Iterating over complex

values

Your list maybe contains some comma or two words but you want to deal with them as one item on the list.

do

echo The $var item

(28)

We play nice till now, always we do. Just keep reading and practicing.

Reading values from a

command

Another way to a list is to use the output of a command. You use command substitution to execute any command that produces output.

echo "This is: $var"

done

#!/bin/bash file="myfile"

for var in $(cat $file)

do

echo " $var"

(29)

Notice that our file contains one word per line, not separated by spaces.

The for command still iterates through the output of the cat command one line at a time, assuming that each line has one word.

However, this doesn’t solve the problem of having spaces in data.

If you list that contains words with spaces in it, the for command still takes each word as a separate value. There’s a reason for this, which we look at now.

The field separator

The cause of this problem is the special environment variable IFS, called the internal field separator. By default, the bash shell considers the following characters as field

(30)

the data, it assumes that you’re starting a new data field in the list.

To solve this problem, you can temporarily change the IFS environment variable values in your bash script suppose that you want to separate by new lines so it will be like this

So after you add this to your bash script it will ignore spaces and tabs and consider new lines as a separator.

You got it. Bash scripting is easy just little attention

IFS=$'\n'

#!/bin/bash

file="/etc/passwd"

IFS=$'\n'

for var in $(cat $file)

do

echo " $var"

(31)

In this case, the separator is colon like the case of /etc/passwd file which contains the user’s information you can assign it like this

How bash scripting is awesome?

Iterating over directory

files

One of the most common things when using for loop in bash scripting is iterate over files in a directory and deal with them.

For example, we want to list the file inside /home directory so the code will be like this

IFS=:

#!/bin/bash

for file in /home/likegeeks/*

do

(32)

From the previous post, you should know the if statement and how to differentiate between files and folders, so if you don’t know I

recommend you to review it bash script step by step.

Here we use wildcard character which is

asterisk * and this is called in bash scripting file

globbing which is a process of producing

filenames automatically that matches the wildcard character in our case asterisk means

echo "$file is a file"

fi done

(33)

Sure enough, it lists all files and directories in that folder

for Command C-Style

If you know c language you may found that the for loop here is weird because you are familiar with this syntax

for (i = 0; i < 10; i++)

{

printf(“number is %d\n”, i);

}

The bash scripting also supports a version of the for loop that looks similar to the C-style for loop with little difference here’s the syntax.

for (( variable assignment ; condition ; iteration

process ))

(34)

And this is the output

The while Command

The for loop is not the only way of looping in bash scripting. The while command allows you to define a command to test and then loop through a set of commands as long as the

defined test command returns a zero exit status which means success. It tests the test

command at the start of each iteration. When the test command returns a nonzero exit status

for (( i=1; i <= 10; i++ ))

do

echo "number is $i"

(35)

while test command

do

other commands

done

and here is an example

The script is simple; it starts with while

command to check if var1 is greater than zero then the loop will run and the var1 value will be decreased every time by 1 and on ever loop iteration it will print the value of var1, Once the var1 value is zero the loop will exit.

#!/bin/bash var1=5 while [ $var1 -gt 0 ] do echo $var1 var1=$[ $var1 - 1 ] done

(36)

If we don’t decrease the value of var1 it will be the same value and the loop will be infinite.

Nesting Loops

A loop statement can use any other type of command within the loop, including other loop commands. This is called a nested loop.

Here’s an example of nested loops.

As you can see from the results the outer loop hits first then goes into the inner loop and

completes it and go back to the outer loop and

#!/bin/bash

for (( a = 1; a <= 3; a++ ))

do

echo "Start $a:"

for (( b = 1; b <= 3; b++ ))

do

echo " Inner loop: $b"

done done

(37)

Looping on File Data

This is the most common usage for the for loop in bash scripting.

We can iterate over file content for example /etc/passwd file and see what we will get

#!/bin/bash

IFS=$'\n'

for entry in $(cat /etc/passwd)

do

echo "Values in $entry –"

IFS=:

for value in $entry

do

echo " $value"

done done

(38)

You can apply this idea when you have CSV or any comma separated values file or whatever. The idea is the same; you just will change the separator to fit your needs.

Controlling the Loop

Maybe after the loop starts you want to stop at a specific value, will you wait until the loop is finished? Of course not, there are two

commands help us in this.

(39)

any type of loop, including while and until loops.

The for loop should normally have iterated through all the values in the list.

However, the shell executed the break command, which stopped the for loop

#!/bin/bash for var1 in 1 2 3 4 5 6 7 8 9 10 do if [ $var1 -eq 5 ] then break fi

echo "Number: $var1"

(40)

The while loop terminated when the if-then condition was met, executing the break command.

The continue command

The continue command is a way to prematurely stop processing commands inside of a loop but not terminate the loop completely.

do

if [ $var1 -eq 5 ]

then break fi

echo "Iteration: $var1"

var1=$(( $var1 + 1 ))

(41)

When the conditions of the if-then statement are met (the value is greater than 5 and less than 10), the shell executes the continue command, which skips the rest of the commands in the loop, but keeps the loop going.

Processing the Output of

do

if [ $var1 -gt 5 ] && [ $var1 -lt 10 ]

then continue fi

echo "Iteration number: $var1"

(42)

the done command.

So instead of displaying the results on screen, the shell redirects the results of the for

command to the file or whatever

The shell creates the file myfile.txt and

redirects the output of the for command to the file. And if we check that file we will find our loop output inside it.

Let’s employ out bash scripting knowledge in something useful.

#!/bin/bash

for (( a = 1; a < 10; a++ ))

do

echo "Number is $a"

done > myfile.txt

(43)

available on your system for you to use, just scan all the folders in the PATH environment variable. We discussed for loop and if

statements and file separator so our toolset is ready. Let’s combine them together and make something pretty

This is just awesome. We were able to get all the executables on the system that we can run

#!/bin/bash

IFS=:

for folder in $PATH

do

echo "$folder:"

for file in $folder/*

do if [ -x $file ] then echo " $file" fi done done

(44)

Now nothing stops you except your

imagination. And this is the beauty of bash scripting

This for now, I hope you enjoy the article and learn a new thing or at least review your knowledge if you forget it. My last word is keep reading and practicing.

(45)

LINUX

Linux Bash Scripting The

Awesome Guide Part3

February 12, 2017 admin 2 Comments

So far you’ve seen how to write Linux bash scripts that interact with data, variables, and files and how to control the flow of the bash script Today we will continue our series about

Linux bash scripting.

I recommend you to review the previous posts if you want to know what we are talking about.

bash scripting part1

bash scripting part2

(46)

Grabbing all parameters

Shift command

Bash scripting options

Separating options from parameters

Processing options with values

Standardizing Options

Getting User Input

Reading password

Reading from a file

Today we will know how to retrieve input from the user and deal with that input so our script becomes more interactive.

The most basic method of passing data to your shell script is to use command line parameters.

(47)

This example passes two command line

parameters (10 and 20) to the script. So how to read those parameters in our bash script?

Reading parameters

The bash shell assigns special variables, called positional parameters, to all of the command line parameters entered

$0 being the script’s name $1 being the first parameter

$2 being the second parameter, and so on,

up to $9 for the ninth parameter

Here’s a simple example how to use command line parameter in a shell script

#!/bin/bash

echo $0

echo $1

echo $2

(48)

If you need to enter more command line parameters, each parameter must be separated by a space

Here is another example of how we can use two parameters and calculate the sum of them

The parameters is not restricted to numbers it could be strings like this

#!/bin/bash

total=$[ $1 + $2 ]

echo The first parameter is $1.

echo The second parameter is $2.

echo The sum is $total.

(49)

And the result is as expected.

But what if our parameter contains a space and we want to pass it as one value? I guess you know the answer from the previous posts. The answer is to use quotations.

If your script needs more than nine parameters, you must use braces around the variable

number, such as ${10}.

Testing parameters

If the script is run without the parameters and your code expecting it, you’ll get an error message from your script.

So Always check your parameters to make sure that they exist

#!/bin/bash if [ -n "$1" ]

(50)

Counting parameters

You can count how many parameters were entered on the command line. The bash shell provides a special variable for this purpose.

The special $# variable contains the number of the command line.

How awesome is Linux bash scripting? this variable also provides a geeky way of getting

./myscript 1 2 3 4 5

fi

#!/bin/bash

(51)

Grabbing all parameters

In some situations, you want to grab all the parameters provided.

The $* and $@ variables in Linux bash scripting provides you all of your parameters. Both of these variables include all the command line parameters within a single variable. So you don’t have to grab them by $# variable and iterate over them, just one step

The $* variable takes all the parameters

supplied on the command line as a single word.

The $@ variable takes all the parameters as separate words in the same string, It allows you to iterate through them

This code shows the difference between them

(52)

Both variables produce the same output but if you want to know the difference look at the following example

Now you see the difference.

#!/bin/bash

count=1

for param in "$*"

do

echo "\$* Parameter #$count = $param"

count=$(( $count + 1 ))

done

count=1

for param in "$@"

do

echo "\$@ Parameter #$count = $param"

count=$(( $count + 1 )) done

(53)

$* variable treated all the parameters as a

single parameter, while the $@ variable treated each parameter separately. So you can use any one of those variables according to your needs

Shift command

The shift command has some little risk in Linux bash scripting it literally shifts the command line parameters in their relative positions.

When you use the shift command, it moves each parameter variable one position to the left by default. So, the value for variable $3 is

moved to $2, the value for variable $2 is moved to $1, and the value for variable $1 is discarded (note that the value for variable $0, the script name, remains unchanged).

This is another great way to iterate through parameters

#!/bin/bash

(54)

Here the script performs a while loop, checking the length of the first parameter’s value. When The first parameter’s length is zero, the loop ends. After testing the first parameter, the shift command is used to shift all the parameters one position.

Careful when using shift command because when a parameter is shifted its value is removed and cannot be recovered.

Bash scripting options

Options are single letters preceded by a dash that alters the behavior of a command.

shift

done

#!/bin/bash

(55)

The case statement checks each parameter for valid options. When one is found, the

appropriate commands are run in the case statement.

Separating options from

parameters

$ ./myscipt –a –b –c –d

-b) echo "Found the -b option" ;; -c) echo "Found the -c option" ;; *) echo "$1 is not an option" ;;

esac shift

(56)

the options are finished and when the normal parameters start.

This special character is the double dash (–). The shell uses the double dash to indicate the end of the options list. After seeing the double dash, your script can safely process the

remaining command line parameters as parameters and not options

#!/bin/bash

while [ -n "$1" ]

do

case "$1" in

-a) echo "Found the -a option" ;; -b) echo "Found the -b option";; -c) echo "Found the -c option" ;; --) shift

break ;;

*) echo "$1 is not an option";;

esac shift

(57)

This bash script uses the break command to break out of the while loop when it encounters the double dash.

As you can see from the result when the script reaches the double dash, it stops processing options and assumes that any remaining parameters are command line parameters. I love Linux bash scripting.

Processing options with

values

When you dig deep onto Linux bash scripting Sometimes you need options with additional

echo "Parameter #$count: $param"

count=$(( $count + 1 )) done

(58)

command line option requires an additional parameter and be able to process it.

#!/bin/bash

while [ -n "$1" ]

do

case "$1" in

-a) echo "Found the -a option";; -b) param="$2"

echo "Found the -b option, with parameter value $param"

shift ;;

-c) echo "Found the -c option";; --) shift

break ;;

*) echo "$1 is not an option";;

esac shift done count=1 for param in "$@" do

(59)

In this example, the case statement defines three options that it processes.

The -b option also requires an additional

parameter value. Because the parameter being processed is $1, you know that the additional parameter value is located in $2 (because all the parameters are shifted after they are processed). Just extract the parameter value from the $2 variable. Of course, because we used two parameter spots for this option, you also need to set the shift command to shift one additional position.

Well, that works well but there are limitations. For example, this doesn’t work if you try to combine multiple options in one parameter like this

(60)

processing options that can help you in this situation

Standardizing Options

When you start your Linux bash scripting, it’s completely up to you to choose which letter options you select to use and how you select to use them.

However, a few letter options have achieved a somewhat standard meaning in the Linux

world.

And here is the list of the common options

-a        Shows all objects

-c        Produces a count

-d        Specifies a directory

-e        Expands an object

(61)

-l         Produces a long format version of the output

-n        Uses a non-interactive (batch) mode

-o        Specifies an output file to redirect all output to

-q        Runs in quiet mode

-r       Processes directories and files recursively

-s        Runs in silent mode

-v        Produces verbose output

-x        Excludes an object

-y      Answers yes to all questions

If you work with Linux You’ll probably recognize most of these option meanings.

(62)

Providing command line options and

parameters is a great way to get data from your bash script users, but sometimes your script needs to be more interactive.

Sometimes you need data from the user while the bash scripting is running.

The bash shell provides the read command just for this purpose.

The read command accepts input either from standard input (the keyboard) or from another file descriptor. After receiving the input, the read command places the data into a variable and here is an example.

Notice that the echo command that generated the prompt uses the –n option. This prevents the newline character at the end of the string,

#!/bin/bash

echo -n "Enter your name: "

read name

(63)

You can specify multiple variables like this

If you don’t specify any variable for read

command the read command places any data it receives in the special environment variable REPLY.

If your bash script must go on regardless of

#!/bin/bash

read -p "Enter your name: " first last echo "Your data for $last, $first…"

#!/bin/bash

read -p "Enter your name: "

(64)

If you do not enter data for five seconds the script will execute the else clause and print sorry message

Reading password

In Linux bash scripting Sometimes you don’t want that input to display on the screen like entering a password.

The -s option prevents the data entered in the read command from being displayed on the screen.

#!/bin/bash

if read -t 5 -p "Enter your name: " name

then

echo "Hello $name, welcome to my script"

else

echo "Sorry, too slow! "

(65)

Reading from a file

The read command reads a single line of text from the file on each call.

When no more lines are left in the file, the read command just stop.

Now if you want to get all file data you can pipe the result of cat command of the file to while command that contains read command (I know the cat command smells like noob but I want beginners and gurus got my point).

read -s -p "Enter your password: " pass echo "Is your password really $pass? "

#!/bin/bash

count=1

cat myfile | while read line

(66)

We just pass the file content to while loop and iterate over every line and print the line

number and the content and each time you increase the count by one simple enough huh?

I hope you find this post interesting and I’m going to make more posts about Linux bash scripting

(67)

On the previous post we’ve talked about

parameters and options in detail and today we will talk about something is very important in shell scripting which is input & output & redirection.

So far, you’ve seen two methods for displaying the output from your shell scripts

Displaying output on the screen Redirecting output to a file

Sometimes you need to display some data on the screen and other data in a file so you need to know how Linux handles input and output so you can get your shell script output to the right place

Our main points are: Standard file descriptors

STDIN (Standard Input)

(68)

Redirecting output in shell scripts

Redirecting Input in shell scripts

Creating your own redirection

Creating input file descriptors

Closing file descriptors

Listing open file descriptors

Suppressing command output

Standard file descriptors

Everything is a file in Linux and that includes input and output and Linux identifies each file using the file descriptor.

Each process is allowed to have up to nine open file descriptors at a time. The bash shell

reserves the first three file descriptors 0, 1, 2

(69)

input and output from your shell script.

You need to fully understand those three because those are like the backbones of your shell scripting, so we are going to describe every one of them in detail.

STDIN

This stands for the standard input to the shell. For a terminal interface, the standard input is the keyboard.

When you use the input redirect symbol (<) in shell scripting, Linux replaces the standard input file descriptor with the file referenced. It reads the file and sends the data just as if it were typed on the keyboard No magic.

Many bash commands accept input from STDIN If no files are specified on the command line like cat command.

When you enter the cat command on the command line without anything, it accepts

(70)

This stands for the standard output for the shell. The standard output is the screen.

Most bash commands direct their output to the STDOUT file descriptor by default which is the screen.

You can also append data to a file. You do this using the >> symbol.

So if we have a file contains data we can

append another data to it using this symbol like this

The output generated by pwd is appended to myfile without deleting the existed content.

Fine but if you try to redirect something and that command run into a problem

(71)

Here there is no file called xfile on my PC and it generates error and the shell doesn’t redirect the error message to the output redirection file but the error message appeared on the screen and here is the third type of file descriptors

STDERR

This file descriptor standard error output for the shell

By default, the STDERR file descriptor points to the same place as the STDOUT file descriptor that’s why when an error occurs you see the error on the screen.

So you need to redirect the errors to maybe log file or any else instead of printing it on the

screen

Redirecting errors

As we see the STDERR file descriptor is set to the value 2. We can redirect the errors by

(72)

As you see the error now is in the file and nothing on the screen

Redirecting errors and

normal output

In shell scripting, if you want to redirect both errors and the normal output, you need to precede each with the appropriate file

descriptor for the data you want to redirect like this

cat ./myfile

ls –l myfile xfile anotherfile 2>

(73)

using the 2> symbol.

If you want, you can redirect both STDERR and STDOUT output to the same output file use &> symbol like this

All error and standard output are redirected to file named content.

Redirecting Output in

Scripts

There are two methods for redirecting output in shell scripting

Temporarily redirection

ls –l myfile xfile anotherfile &> content

(74)

You can redirect an individual output line to STDERR. You just need to use the output

redirection symbol to redirect the output to the STDERR file descriptor and you must precede the file descriptor number with an ampersand (&) like this

So if we run it we will see both lines printed normally because as we know STDERR output to STDOUT if you redirect STDERR when

running the script we should do it like this

./myscript 2> myfile

#!/bin/bash

echo "This is an error" >&2

(75)

Permanent redirections

If you have lots of data that you’re redirecting in your script, it would be hard to redirect every echo statement. Instead, you can redirect to a specific file descriptor for the duration of the script by using the exec command.

If we look at the file called outfile we will see the output of echo lines.

You can also redirect the STDOUT in the middle

#!/bin/bash

exec 1>outfile

echo "This is a test of redirecting all output"

echo "from a shell script to another file."

(76)

The exec command redirects any output going to STDERR to the file myerror. Then, the script uses the echo statement to display a few lines to STDOUT which is the screen.

After that, the exec command is used again to redirect STDOUT to the myfile file and finally, we redirect the error from within the echo

statement to go to STDERR which in this case is myerror file.

Now you have all the ability to redirect all of your output to whatever you want Excellent!

echo "now redirecting all output to another location"

exec 1>myfile

echo "This should go to the myfile file"

(77)

exec command allows you to redirect STDIN from a file.

This command tell the shell to take the input from the file called myfile instead of STDIN and here is an example

Shell scripting is easy.

exec 0< myfile

#!/bin/bash

exec 0< testfile

count=1

while read line

do

echo "Line #$count: $line"

count=$(( $count + 1 )) done

(78)

file instead of the keyboard.

Some Linux system administrators use this technique to read the log files for processing and we will discuss more ways to read the log on the upcoming posts more professionally.

Creating Your Own

Redirection

When you redirect input and output in your shell script, you’re not limited to the three

default file descriptors. As I mentioned that you could have up to nine open file descriptors in the shell. The other six file descriptors from 3 through 8 and are available for you to use as either input or output redirection. You can

assign any of these file descriptors to a file and then use them in your shell scripts

You can assign a file descriptor for output by using the exec command and here’s an

(79)

Creating input file

descriptors

You can redirect input file descriptors in shell scripting exactly the same way as output file descriptors. Save the STDIN file descriptor location to another file descriptor before redirecting it to a file.

When you’re finished reading the file, you can restore STDIN to its original location

echo "And this should be back on the screen"

#!/bin/bash

exec 6<&0

exec 0< myfile

count=1

while read line

(80)

In this example, file descriptor 6 is used to hold the location for STDIN. The shell script then redirects STDIN to a file. All the input for the read command comes from the redirected STDIN, which is now the input file.

After all the lines have been read, the shell script returns STDIN to its original location by redirecting it to file descriptor 6. And the shell script makes sure that STDIN is back to normal by using another read command and now it is

read -p "Are you done now? " answer

case $answer in

y) echo "Goodbye";;

n) echo "Sorry, this is the end.";; esac

(81)

descriptors when the script exits. There are situations you need to manually close a file descriptor before the end of the script. To close a file descriptor, redirect it to the special

symbol &- like this

As you can see it gives error bad file descriptor because it is no longer exist

Note: careful in shell scripting when closing file descriptors. If you open the same output file later on in your shell script, the shell replaces

exec 3

>&-#!/bin/bash

exec 3> myfile

echo "This is a test line of data" >&3

exec 3

(82)

descriptors

The lsof command lists all the open file descriptors on the entire Linux system

On many Linux systems like Fedora, the lsof command is located in the /usr/sbin.

This command is very useful actually it displays information about every file currently open on the Linux system. This includes all the

processes running on background, as well as any user accounts logged into the system.

This command has a lot of options so I think I will make a special post about it later but let’s take the important parameters we need

-p, allows you to specify a process ID

-d, allows you to specify the file descriptor numbers to display

To get the current PID of the process, you can use the special environment variable $$, which

(83)

The file type associated with STDIN, STDOUT, and STDERR is character mode. Because the STDIN, STDOUT, and STDERR file descriptors all point to the terminal, the name of the output file is the device name of the terminal. All three standard files are available for both reading and writing.

Now, let’s look at the results of the lsof

command from inside a script that’s opened a couple of alternative file descriptors

lsof -a -p $$ -d 0,1,2 #!/bin/bash exec 3> myfile1 exec 6> myfile2 exec 7< myfile3 lsof -a -p $$ -d 0,1,2,3,6,7

(84)

two for output (3 and 6) and one for input (7).

And you can see the pathname for the files used in the file descriptors.

Suppressing Command

Output

Sometimes you don’t want to see any output this often occurs if you’re running a script as a background process (we will discuss how to make you shell script run in the background in the next posts)

We redirect the output to the hole which is /dev/null

For example, we can suppress errors like this

And this idea is also used when you want to truncate a file without deleting it completely

ls -al badfile anotherfile 2> /dev/null

(85)

I hope you enjoy it; the next post will be how to control our running script and how to run your shell script in the background without

interruption and how to pause them while they are running and some other cool stuff, Stay tuned.

Thanks

LINUX

Linux Bash Scripting The

Awesome Guide Part5

February 15, 2017 admin 0 Comments

(86)

command line interface in real-time mode. This isn’t the only way to run Linux bash scripts in Linux.

Our main points are: Linux signals

Stop a process

Pause a process

Trapping signals

Trapping the script exit

Modifying or removing a trap

Running scripts in background mode

Running Scripts without a Hang-Up

Viewing jobs

(87)

Starting scripts with a new shell

There are various control methods include sending signals to your script, modifying a script’s priority, and switching the run mode while a script is running. This post describes the different ways you can control your Linux bash scripts.

Linux signals

There are more than 30 Linux signals that can be generated by the system and applications and this is the most common Linux system signals that you’ll run across in your Linux bash script writing

Signal    Value   Description

1        SIGHUP         Hangs up the process

2        SIGINT        Interrupts the process

(88)

15       SIGTERM       Terminates the process if possible

17           SIGSTOP        Unconditionally stops, but doesn’t terminate, the process

18       SIGTSTP        Stops or pauses the process, but doesn’t terminate

19           SIGCONT       Continues a stopped process

If the bash shell receives a SIGHUP signal, such as when you leave an interactive shell, it exits. Before it exits, it passes the SIGHUP signal to any processes started by the shell, including any running shell scripts

With a SIGINT signal, the shell is just

interrupted. The Linux kernel stops giving the shell processing time on the CPU. When this happens, the shell passes the SIGINT signal to any processes started by the shell to notify them.

(89)

Generating signals

The bash shell allows you to generate two basic Linux signals using key combinations on the keyboard. This feature comes in handy if you need to stop or pause a running bash script

Stop a process

The Ctrl+C key combination generates a SIGINT signal and sends it to any processes currently running in the shell which simply stops the current process running in the shell.

Ctrl+C

Pause a process

The Ctrl+Z key combination generates a $ sleep 100

(90)

Ctrl+Z

The number in the square brackets is the job

number assigned by the shell. The shell refers

to each process running in the shell as a job which is unique. It assigns the first started process job number 1, the second job number 2, and so on

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

You can view the stopped jobs using the ps command

$ sleep 100

(91)

In the S column (process state), shows the stopped job’s state as T. This indicates the command is either being traced or is stopped

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

recommend you to review the basic Linux commands if you need more info about kill command

Trapping signals

The trap command allows you to specify which Linux signals your shell script can watch for and intercept from the shell. If the script receives a signal listed in the trap command, it prevents it from being processed by the shell and instead handles it locally.

So instead of allowing your Linux bash script to leave signals ungoverned, you can use trap command to do that.

(92)

The trap command used in this example displays a simple text message each time it detects the SIGINT signal when hitting Ctrl+C.

Each time the Ctrl+C key combination was

#!/bin/bash

trap "echo ' Trapped Ctrl-C'" SIGINT echo This is a test script

count=1

while [ $count -le 10 ]

do

echo "Loop #$count"

sleep 1

count=$(( $count + 1 )) done

(93)

You can trap them when the shell script exits; just add the EXIT signal to the trap command

When the Linux bash script gets exit, the trap is triggered and the shell executes the echo

command specified

#!/bin/bash

trap "echo Goodbye..." EXIT

count=1

while [ $count -le 5 ]

do

echo "Loop #$count"

sleep 1

count=$(( $count + 1 )) done

(94)

trap

You can reissue the trap command with new options

#!/bin/bash

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

count=1

while [ $count -le 5 ]

do

echo "Loop #$count"

sleep 1

count=$(( $count + 1 ))

done

trap "echo ' I modified the trap!'" SIGINT

count=1

while [ $count -le 5 ]

do

echo "Second Loop #$count"

sleep 1

count=$(( $count + 1 )) done

(95)

After the signal trap is modified, the bash script manages the signal or signals differently.

You can also remove a set trap. Simply add two dashes after the trap command

#!/bin/bash

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

count=1

while [ $count -le 5 ]

do

echo "Loop #$count"

sleep 1

count=$(( $count + 1 ))

done

trap -- SIGINT

echo "I just removed the trap"

count=1

while [ $count -le 5 ]

(96)

If a signal is received before the trap is

removed, the script processes it per the original trap command

Crtl+C

The first Ctrl+C were used to attempt to terminate the script. Because the signal was received before the trap was removed, the script executed the echo command specified in the trap. After the script executed the trap removal, then Ctrl+C could terminate the bash script

Running Linux bash

scripts in background

(97)

can’t do anything else in your terminal session. Fortunately, there’s a simple solution to that problem.

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

$ ./myscipt & #!/bin/bash count=1 while [ $count -le 10 ] do sleep 1 count=$(( $count + 1 )) done

(98)

done.

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

If the terminal session exit, the background process also exit

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

(99)

blocking any SIGHUP signals that are sent to the process. This prevents the process from exiting when you exit your terminal.

The nohup command disassociates the process from the terminal, the process loses the

STDOUT and STDERR output links. To

accommodate any output generated by the command, the nohup command automatically redirects STDOUT and STDERR messages to a file, called nohup.out

Note when running multiple commands from the same directory, because all the output is sent to the same nohup.out file

Viewing jobs

The jobs command allows you to view the $ nohup ./myscript &

(100)

Then run it

Then stop it using the Ctrl+Z

Run the same bash script but in background using the ampersand symbol and to make life a little easier, I’m going to make the output of that script is redirected to a file so it doesn’t appear on the screen

$ ./myscript

$ ./myscript > outfile &

do

echo "Loop #$count"

sleep 10

count=$(( $count + 1 )) done

(101)

The jobs command shows both the stopped and the running jobs

-l parameter to view the process ID

Restarting stopped jobs

To restart a job in background mode, use the bg command

Ten press Ctrl+z

Now it is stopped

As you can see it is now running in background

jobs –l

$ ./myscript

(102)

To restart a job in foreground mode, use the fg command.

Scheduling a job

The Linux system provides a couple of ways to run a bash script at a preselected time: the at command and the cron table

The at command

This is the format of the command

at [-f filename] time

The at command recognizes lots of different time formats

A standard hour and minute, such as 10:15 An AM/PM indicator, such as 10:15PM

A specific named time, such as now, noon, midnight

(103)

MM/DD/YY, or DD.MM.YY

A text date, such as Jul 4 or Dec 25, with or without the year

Now + 25 minutes 10:15PM tomorrow 10:15 + 7 days

We don’t want to dig deep into the at command but for now, just make it simple and we will discuss it in detail in future posts.

The –M parameter is to send output to e-mail if the system has e-mail and if not this will

suppress the output of the at command

To list the pending jobs use atq command $ at -f ./myscript now

(104)

you can use the atrm command to remove a pending job by specifying the job number

Scheduling scripts

Using the at command to schedule a script to run at a preset time is great, but what if you need that script to run at the same time every day or once a week or once a month.

The Linux system uses the crontab command to allow you to schedule jobs that need to run

regularly.

The crontab program runs in the background and checks special tables, called cron tables, for jobs that are scheduled to run

To list an existing cron table, use the -l $ atrm 18

(105)

minute,Hour, dayofmonth, month, and dayofweek

So if you want to run a command at 10:30 on every day, you would use this cron table entry

30 10 * * * command

The wildcard character (*) used in the dayofmonth, month, and dayofweek fields indicates that cron will execute the command every day of every month at 10:30.

To specify a command to run at 4:30 PM every Monday, you would use the following

30 16 * * 1 command

The day of the week start from 0 to 6 where 0 is Sunday and 6 is Saturday

Here’s another example: to execute a

command at 12 noon on the first day of every month, you would use the following format

(106)

the cron in great detail in future posts.

To add entries to your cron table, use the -e parameter like this

Then type your command like the following

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 root user

Just that simple!

You can use one of the pre-configured cron

crontab –e

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

(107)

/etc/cron.daily

/etc/cron.weekly

/etc/cron.monthly

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

Starting scripts with a

new shell

Remember from the previous posts we’ve talked about startup files I recommend you to review the previous posts to get the point.

$HOME/.bash_profile

$HOME/.bash_login

$HOME/.profile

Just place any scripts you want to run at login time in the first file listed.

(108)

execute that command

This for now, I hope you find the post useful.

Thanks.

LINUX

Bash Scripting The

Awesome Guide Part6 Bash

Functions

February 17, 2017 admin 2 Comments

Before we talk about bash functions let’s discuss this situation. When writing bash scripts, you’ll find yourself that you are using

(109)

refer to that block of code anywhere in your bash script without having to rewrite it.

The bash shell provides a feature allowing you to do just that called Functions.

Bash functions are blocks of script code that

you assign a name to and reuse anywhere in your code. Anytime you need to use that block of code in your script, you simply use the

function name you assigned it.

We are going to talk about how to create your own bash functions and how to use them in other shell scripts.

Our main points are: Creating a function

Using functions

Using the return command

(110)

Recursive function

Creating libraries

Use bash functions from command line

Creating a function

You can create a function like this

functionName {

}

Or like this

functionName() {

}

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

Using functions

(111)

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

The function can be called many times as you want.

Notice: If you attempt to use a function before it’s defined, you’ll get an error message

while [ $count -le 3 ]

do

myfunc

count=$(( $count + 1 ))

done

echo "This is the end of the loop"

myfunc

echo "End of the script"

(112)

Another notice: bash function name must be unique, or you’ll have a problem. If you redefine a function, the new definition overrides the

original function definition without any errors count=$(( $count + 1 ))

done

echo "This is the end of the loop"

function myfunc {

echo "This is an example of using a function"

}

echo "End of the script"

#!/bin/bash

function myfunc {

echo "The first function definition"

}

myfunc

(113)

As you 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 allows you to specify a single integer value to define the function exit status.

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 )) }

(114)

The myfunc function adds 10 to the value contained in the $value variable provided by the user input. It then returns the result using the return command, which the script displays using the $? Variable.

If you execute any other commands before retrieving the value of the function, using the $? variable, the return value from the function is lost. Remember that the $? Variable returns the exit status of the last executed command.

You cannot use this return value technique if you need to return either larger integer values or a string value.

Using function output

The second way of returning a value from a bash function is to capture the output of a command to a shell variable; you can also capture the output of a function to a shell

(115)

Passing parameters to a

function

We can deal with bash functions like small

snippets that we can reuse and that’s ok but we need to make the function like an engine, we give it something and it returns another thing based on what we gave.

Functions can use the standard parameter environment variables to represent any parameters passed to the function on the command line. For example, the name of the

function myfunc {

read -p "Enter a value: " value echo $(( $value + 10 ))

}

result=$( myfunc)

(116)

parameters passed to the function. I

recommend you to review the previous posts to empower your knowledge about them on Linux bash scripting.

We pass parameters to functions on the same command line as the function, like this

The following example shows you how to retrieve the parameter values using the parameter environment variables

myfunc $val1 10 20 #!/bin/bash function addnum { if [ $# -eq 0 ] || [ $# -gt 2 ] then echo -1 elif [ $# -eq 1 ] then echo $(( $1 + $1 )) else

(117)

The addnum function checks the number of parameters passed to it by the script. If there are no parameters, or if there are more than two parameters, addnum returns a value of -1. If there’s one parameter, addnum adds the parameter to itself for the result. If there are

value=$(addnum 10 15)

echo $value

echo -n "Adding one number: "

value=$(addnum 10)

echo $value

echo -n "Adding no numbers: "

value=$(addnum)

echo $value

echo -n "Adding three numbers: "

value=$(addnum 10 15 20)

(118)

values from the command line of the script. The following example fails

Instead, if you want to use those values in your bash function, you have to manually pass them when you call the function like this

#!/bin/bash function myfunc { echo $(( $1 + $2 )) } if [ $# -eq 2 ] then value=$( myfunc)

echo "The result is $value"

else

echo "Usage: myfunc  a b"

(119)

Now they are available for the function to use, just like any other parameter

Handling variables in

bash functions

Every variable we use has a scope, the scope is where the variable is visible

Variables defined inside functions can have a different scope than regular variables.

if [ $# -eq 2 ] then

value=$(myfunc $1 $2)

echo "The result is $value"

else

echo "Usage: myfunc a b"

(120)

Local

Global variables

Global variables are variables that are visible and valid anywhere in the bash script. If you define a global variable in the main section of a script, you can retrieve its value inside a

function.

The same, if you define a global variable inside a function, you can retrieve its value in the main section of the script.

By default, any variables you define in the script are global variables. Variables defined outside of a function can be accessed inside the function without problems

#!/bin/bash

function myfunc {

value=$(( $value + 10 )) }

read -p "Enter a value: " value myfunc

(121)

When the variable is assigned a new value inside the function, that new value is still valid when the script references the variable as the above example the variable $value is changed inside the function.

So how to overcome something like this; Use local variables

Local variables

Any variables that the bash function uses

internally can be declared as local variables. To do that, just use the local keyword in front of the variable like this

If a variable with the same name appears outside the function in the script, the shell keeps the two variable values separate. Now you can easily keep your function variables separate from your script variables

local temp=$(( $value + 5 ))

(122)

Now when you use the $temp variable inside the myfunc function, it doesn’t affect the value assigned to the $temp variable in the main script.

Passing arrays to

functions

The art of passing an array variable to a bash function can be confusing. If you try to pass the array variable as a single parameter, it doesn’t work

temp=4

myfunc

echo "The temp from outside is $temp"

#!/bin/bash

function myfunc {

References

Related documents

Favor you leave and sample policy employees use their job application for absence may take family and produce emails waste company it discusses email etiquette Deviation from

Modeling complex metabolic reactions, ecological systems, and financial and legal networks with MIANN models based on Markov-Wiener node descriptors.. Aliuska

In summary, the time path and rate of ICT uptake and performance effects differ across firms, even in similar circumstances, due to differences in: the implementation of

Using a spatial working memory task, Azuma and colleagues found lower activation in a parietal region in patients with 22q11 deletion syndrome compared with healthy controls,

Furthermore, while symbolic execution systems often avoid reasoning precisely about symbolic memory accesses (e.g., access- ing a symbolic offset in an array), C OMMUTER ’s test

Conflict predicates can be (almost) arbitrarily complex 1 and depend on many different states. They can be incredibly precise, describing exactly those combinations of state

All stationary perfect equilibria of the intertemporal game approach (as slight stochastic perturbations as in Nash (1953) tend to zero) the same division of surplus as the static

For the poorest farmers in eastern India, then, the benefits of groundwater irrigation have come through three routes: in large part, through purchased pump irrigation and, in a