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
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
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
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
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
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
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
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
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
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 scriptThere 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
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
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
fi
and here is an example
#!/bin/bash if pwd
then
echo "It works"
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"
if-then-else Statement
The if-then-else statement looks like thisif command then commands else commands fi
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
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"
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
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"
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]
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"
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"
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"
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
-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"
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
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
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
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
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"
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 fieldthe 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"
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
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
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 ))
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"
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
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
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
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.
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"
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 ))
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"
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
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
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.
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
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.
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
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.
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" ]
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
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
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
$* 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
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
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
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
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
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
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
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
-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.
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
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: "
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! "
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
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
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)
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
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
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
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
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>
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
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
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."
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"
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
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
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
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
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
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
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
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
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
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
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
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.
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
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
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.
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
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
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
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 ]
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
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
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
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 &
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
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 commandTen press Ctrl+z
Now it is stopped
As you can see it is now running in background
jobs –l
$ ./myscript
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
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
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
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
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
/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.
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
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
Recursive function
Creating libraries
Use bash functions from command line
Creating a function
You can create a function like thisfunctionName {
}
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
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"
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
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 )) }
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 shellPassing 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)
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
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)
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"
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"
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
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 ))
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 {