Bash functions in scripts. BASH: Parsing Bash command line arguments

Having mastered the previous parts of this series of materials, you learned about what bash scripts are, how to write them, how to control the flow of program execution, and how to work with files. Today we will talk about how to add interactivity to scripts by equipping them with the ability to receive data from the user and process this data.

The most common way to pass data to scripts is to use parameters command line. By calling the script with parameters, we pass it some information with which it can work. It looks like this:

$ ./myscript 10 20
IN in this example The script is given two parameters - “10” and “20”. All this is good, but how to read the data in the script?

Reading Command Line Options

The bash shell assigns special variables called positional parameters to the command line parameters entered when calling the script:
  • $0 - script name.
  • $1 is the first parameter.
  • $2 is the second parameter - and so on, up to the variable $9, which contains the ninth parameter.
Here's how to use command line options in a script using these variables:

#!/bin/bash echo $0 echo $1 echo $2 echo $3
Let's run the script with the parameters:

./myscript 5 10 15
This is what it will output to the console.


Displaying the parameters with which the script was launched

Note that command line options are separated by spaces.

Let's look at another example of using parameters. Here we will find the sum of the numbers passed to the script:

#!/bin/bash total=$[ $1 + $2 ] echo The first parameter is $1. echo The second parameter is $2. echo The sum is $total.
Let's run the script and check the result of the calculations.


Script that finds the sum of numbers given to it

Command line options do not have to be numbers. You can also pass strings to scripts. For example, here is a script that works with the string:

#!/bin/bash echo Hello $1, how do you do
Let's run it:

./myscript Adam
He will output what we expect from him.


Script working with string parameter

What if the parameter contains spaces and we need to treat it as a separate piece of data? We believe that if you have mastered the previous parts of this guide, you already know the answer. It involves using quotation marks.

If the script needs more than nine parameters, when accessing them, the number in the variable name must be enclosed in curly braces, for example like this:

Checking parameters

If the script is called without parameters, but their presence is assumed for normal operation of the code, an error will occur. Therefore, it is recommended to always check for the presence of parameters passed to the script when called. For example, it can be organized like this:

#!/bin/bash if [ -n "$1" ] then echo Hello $1. else echo "No parameters found." fi
Let's call the script first with a parameter, and then without parameters.


Calling a script that checks for the presence of command line parameters

Calculation of parameters

In a script, you can count the number of parameters passed to it. The bash shell provides a special variable for this. Specifically, the $# variable contains the number of parameters passed to the script when called.

Let's try it:

#!/bin/bash echo There were $# parameters passed.
Let's call the script.

./myscript 1 2 3 4 5
As a result, the script will report that 5 parameters were passed to it.


Counting the number of parameters in a script

This variable provides an unusual way to obtain the last parameter passed to the script, without requiring knowledge of their number. This is what it looks like:

#!/bin/bash echo The last parameter was $(!#)
Let's call the script and see what it outputs.


Accessing the last parameter

Capture all command line options

In some cases, you need to capture all the parameters passed to the script. To do this, you can use the variables $* and $@ . They both contain all the command line parameters, making it possible to access what is passed to the script without using positional parameters.

The $* variable contains all the parameters entered on the command line as a single “word”.

In the $@ variable, the parameters are broken down into individual “words”. These parameters can be iterated in loops.

Let's look at the difference between these variables using examples. First, let's take a look at their contents:

#!/bin/bash echo "Using the \$* method: $*" echo "-----------" echo "Using the \$@ method: $@"
Here is the output of the script.


Variables $* and $@

As you can see, when outputting both variables, the same thing is obtained. Now let's try to go through the contents of these variables in loops in order to see the difference between them:

#!/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
Take a look at what the script outputs to the console. The difference between the variables is quite obvious.


Parsing $* and $@ variables in a loop

The $* variable contains all the parameters passed to the script as a single piece of data, while in the $@ variable they are represented as independent values. Which variable to use depends on what exactly is needed in a particular scenario.

shift command

The shift command should be used with caution in bash scripts, as it literally shifts the values ​​of positional parameters.

When you use this command, it, by default, shifts the positional parameter values ​​to the left. For example, the value of the variable $3 becomes the value of the variable $2, the value of $2 goes to $1, and what was previously in $1 is lost. Please note that the value of the $0 variable containing the script name does not change.

Using the shift command, let's consider another way to iterate through the parameters passed to the script:

#!/bin/bash count=1 while [ -n "$1" ] do echo "Parameter #$count = $1" count=$(($count + 1)) shift done
The script uses while loop, checking the length of the value of the first parameter. When the length becomes zero, the loop exits. After checking the first parameter and displaying it on the screen, the shift command is called, which shifts the parameter values ​​​​by one position.


Using the shift command to cycle through options

When using the shift command, remember that each time it is called, the value of the $1 variable is permanently lost.

Command line switches

Command line switches usually look like letters preceded by a dash. They serve to manage scripts. Consider this example:

#!/bin/bash echo 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" ;; *) echo "$1 is not an option" ;; esac shift done
Let's run the script:

$ ./myscript –a –b –c –d
And let's analyze what it outputs to the terminal.


Handling keys in a script

This code uses a case construct that checks the key passed to it with the list of keys processed by the script. If the passed value is found in this list, the corresponding branch of code is executed. If, when calling the script, any key is used, the processing of which is not provided, the “*” branch will be executed.

How to distinguish between keys and parameters

Often when writing bash scripts, a situation arises when you need to use both command line parameters and switches. Standard method to do this is to use a special sequence of characters that tells the script when the keys end and normal parameters begin.

This sequence is a double dash (--). The shell uses it to indicate the position at which the list of keys ends. After the script detects a sign of the end of keys, what remains can, without fear of errors, be processed as parameters, and not as keys. Let's look at an example:

#!/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 done count=1 for param in $@ do echo "Parameter #$count: $param" count=$(($count + 1)) done
This script uses the break command to break the while loop when it encounters a double dash in a line.

This is what happens after calling him.


Handling Command Line Switches and Parameters

As you can see, when the script, parsing the data passed to it, finds a double dash, it completes processing the keys and considers everything that has not yet been processed as parameters.

Handling keys with values

As your scripts become more complex, you will encounter situations where regular keys are no longer sufficient, which means you will need to use keys with some kind of value. For example, calling a script that uses this feature looks like this:

./myscript -a test1 -b -c test2
The script must be able to detect when additional parameters are used along with command line switches:

#!/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 echo "Parameter #$count: $param" count=$(($count + 1)) done
Let's call this script like this:

./myscript -a -b test1 -d
Let's look at the results of his work.


Processing key parameters

In this example, three keys are processed in the case construct. The -b switch requires an additional parameter. Since the key being processed is in the variable $1, the corresponding parameter will be in $2 (the shift command is used here, so as it is processed, everything passed to the script is shifted to the left). When we figured this out, all that remains is to extract the value of the $2 variable and we will have the parameter of the desired key. Of course, we'll need another shift command here to get the next key into $1 .

Using standard keys

When writing bash scripts, you can choose any letters for command line switches and arbitrarily set the script's reaction to these keys. However, in Linux world The values ​​of some keys have become somewhat of a standard that is useful to adhere to. Here is a list of these keys:
-a Print all objects.
-c Perform the calculation.
-d Specify directory.
-e Expand the object.
-f Specify the file from which to read data.
-h Display help for the command.
-i Ignore case.
-l Execute full-format data output.
-n Use non-interactive (batch) mode.
-o Allows you to specify the file to which you want to redirect the output.
-q Execute the script in quiet mode.
-r Process folders and files recursively.
-s Execute the script in silent mode.
-v Perform verbose output.
-x Exclude object.
-y Answer “yes” to all questions.

If you work on Linux, you are likely familiar with many of these switches. By using them in their common sense in your scripts, you can help users interact with them without having to worry about reading the documentation.

Receiving data from the user

Command line switches and parameters are a great way to get data from the person using the script, but in some cases you need more interactivity.

Sometimes scripts need data that the user must enter while the program is running. The bash shell has a read command for precisely this purpose.

This command allows you to accept input either from standard input (keyboard) or using other file descriptors. After receiving the data, this command places it in a variable:

#!/bin/bash echo -n "Enter your name: " read name echo "Hello $name, welcome to my program."
Note that the echo command that displays the prompt is called with the -n switch. This causes the line feed to not appear at the end of the prompt, allowing the script user to enter data where the prompt is located rather than on the next line.


Handling user input

When calling read, you can specify multiple variables:

#!/bin/bash read -p "Enter your name: " first last echo "Your data for $last, $first..."
This is what the script will output after running.


Multiple variables in read command

If you call read without specifying a variable, the user's input will be placed in the special REPLY environment variable:

#!/bin/bash read -p "Enter your name: " echo Hello $REPLY, welcome to my program.


Using the REPLY environment variable

If the script must continue execution regardless of whether the user enters some data or not, when calling the read command, you can use the -t switch. Namely, the key parameter specifies the input wait time in seconds:

#!/bin/bash if read -t 5 -p "Enter your name: " name then echo "Hello $name, welcome to my script" else echo "Sorry, too slow! " fi
If no data is entered within 5 seconds, the script will execute the conditional branch else statement, issuing an apology.


Time limit for data entry

Entering passwords

Sometimes what the user enters in response to a script question is best not shown on the screen. For example, this is usually done when asking for passwords. The -s switch to the read command prevents keyboard input from being displayed on the screen. In fact, the data is output, but the read command makes the text color the same as the background color.

#!/bin/bash read -s -p "Enter your password: " pass echo "Is your password really $pass?"
Here's how this script will work.


Entering sensitive data

Reading data from a file

The read command can, each time it is called, read one line of text from a file. When there are no more unread lines left in the file, it will simply stop. If you need to get the entire contents of a file in a script, you can, using a pipeline, pass the results of calling the cat command on the file to the while construct, which contains the read command (of course, using the cat command looks primitive, but our goal is to show everything as simply as possible, focusing on beginners; experienced users will surely understand this).

Let's write a script that uses the approach we just described to reading files.

#!/bin/bash count=1 cat myfile | while read line do echo "Line $count: $line" count=$(($count + 1)) done echo "Finished"
Let's look at him in action.


Reading data from a file

Here we passed the contents of the file into the while loop and iterated through all the lines of this file, displaying the number and contents of each of them.

Results

Today we looked at working with command line switches and parameters. Without these tools, the range of use of scripts is extremely narrow. Even if the script is written, as they say, “for yourself.” Here we also looked at approaches to obtaining data from the user during program execution - this makes scripts interactive.

Next time we'll talk about input and output operations.

Dear readers! Thank you for sharing your experience in the comments to the previous parts of this series of materials. If you have something to say about handling everything that can be passed into a script at startup or while it is running, we are sure that many people will be interested in reading about it.

I created a script with the standard getopt magic, so you can call the script with

Batman-connect -c ffki

How can I add a parameter to call this script with only one parameter without a dash?

batman-connect ffki

so it will interpret this single option as the second argument to -c ?

According to this answer I tried:

If [ $@ = "ffki" ]; then set -- "-c $@" fi

But this results in an error, I think because this line in my script will change it:

# Execute getopt on the arguments passed to this program, identified by the special character $@ PARSED_OPTIONS=$(getopt -n "$0" -o hsrvVi:c: --long "help,start,restart,stop,verbose,vv, version,interface:,community:" -- "$@")

I don't like having to reinstall my entire script, so is there a simple one-liner to just set the first argument to "-c" and the second to "ffki"?

4 Solutions collect form web for “Change bash arguments if only one argument is given”

You can do something like

If [ $# = 1 ]; then # do whatever you"d do when there is only one argument else # do the getopt bits fi # do what you"d do in either case

If -c is the only switch you want to support, then you don't need getopt and can do something like this instead:

#!/bin/bash usage() ( echo "Usage: $0 [ -c ] arg" >&2 exit 1 ) if [ $# = 2 ]; then if [ $1 = "-c" ]; then shift c_switch_value="$1" else usage fi elif [ $# = 1 ]; then c_switch_value="$1" else usage fi

Whether this is more readable is debatable, though.

If [ $# = 1 ]; then # If there is only one argument, replace the current process with the new invocation of the script # the only option will be used as -c option exec "$0" -c "$@" fi

This doesn't answer initial question but this is a workaround that works in my special case.

The command in the if clause expands to [ followed by a list of word substitution expansions that make up the positional parameters followeb with words = ffki ] . Generally speaking, $VAR does not mean "VAR value" when it is outside double quotes, this means "split the VAR value into individual words and interpret them as globes." See Why is my shell script choking on spaces or other special characters?

Also, "$@" is a special case: it expands to a list of positional parameters (without further expansion), rather than to a single word (despite the quotes). You can use "$*" which expands to a single word consisting of positional parameters separated by a space (more precisely, the first character of the IFS value). So to check if there is one positional parameter whose value is ffki you can use

If [ "$*" = "ffki" ]; then

If [ $# -eq 1 ] && [ "$1" = "ffki" ]; then

To change the positioning parameters, you were close: use the builtin set and pass a new set of positional parameters as separate arguments. If there is a risk that the first parameter begins with a - , use set -- ... so that it is not interpreted as an option.

If [ "$*" = "ffki" ]; then set -- -c "ffki" fi

Everyone probably knows that the Bash shell has built-in commands that are not found in the /bin or /usr/bin folders. They are built into the shell and executed as functions. In one of the previous articles we looked at. We discussed almost everything there, how scripts should look like, the use of conditions, loops, variables, but did not stop at functions.

In today's article we will correct this shortcoming. Like any programming language, Bash has functions that can be very useful to use. We'll look at using bash functions, how to write them, and even how to create libraries from these functions.

First we need to understand what a function is in our context. A function is a set of commands, united by one name, that perform a specific task. A function is called by its name, can accept parameters and return the result of its work. In short, Bash functions work the same way as in other programming languages.

The syntax for creating a function is very simple:

function_name () ( command_list )

The function name must not coincide with any existing commands or functions, and all commands in the function body are written on a new line.

Simple function

Let's write a small function that will print a string to the screen:

$vi function.sh

#!/bin/bash
printstr())(
echo "hello world"
}
printstr

Calling a bash function is done by specifying its name, just like any other command. Run our script for execution, do not forget that before doing this you need to give it execution rights:

chmod u+x function.sh

Everything works, now let’s complicate the task, let’s try to pass arguments to the function.

Function Arguments

Function arguments must be passed when called, and they are read in exactly the same way as script arguments. The syntax for calling a function with bash parameters is:

function_name argument1 argument2 ... argumentN

As you can see, everything is quite simple. Parameters are separated by a space. Now let's improve our function so that it outputs the string we specified:

!/bin/bash
printstr())(
echo $1
}
printstr "Hello world"

You can have several parameters:

!/bin/bash
printstr())(
echo $1
echo $2
echo $3
echo $5
}
printstr "arg1" "arg2" "arg3" "arg4" "arg5"

There is another way to retrieve arguments, like in C, using the stack. We pop the first argument, then advance the argument stack pointer by one, and pop the first argument again. And so on:

!/bin/bash
printstr())(
echo $1
shift
echo $1
shift
echo $1
shift
echo $1
}
printstr "arg1" "arg2" "arg3" "arg4"

Returning the result of a function

You can not only use functions with bash parameters, but also get the result of the work from it. The return command is used for this. It terminates the function and returns a numeric return code. It can be from 0 to 255:

!/bin/bash
printstr())(
return 134;
}
printstr
echo $?

If you need to apply the return value of a bash function rather than the status code, use echo. The string is not immediately printed to the terminal, but is returned as the result of the function and can be written to a variable and then used:

!/bin/bash
printstr())(
echo "test"
}
VAR=$(printstr)
echo $VAR

Export functions

You can make a function available outside of a script using the declare command:

!/bin/bash
printstr())(
echo "hello world"
}
declare -x -f printstr

Then run the script using the source command:

source function.sh
$printstr

Recursion

You can call a function from within itself to do recursion:

!/bin/bash
printstr())(
echo "hello world"
printstr
}
printstr

You can experiment with using recursion, which can be useful in many cases, just remember to make the first call to a Bash function.

Local variables in a function

If you declare a regular variable in a function, it will be available throughout the script, this is convenient for returning the value of the function, but sometimes you may need to make it a local variable. There is a local command for this:

!/bin/bash
printstr())(
local VAR=$1
echo $(VAR)
}
printstr "Hello World"

Function libraries

We can take some bash functions and combine them into one library so that we can import these functions with one command. This is done in a similar way to exporting functions. First, let's create a library file:

test1())(
echo "Hello World from 1";
}
test2())(
echo "Hello World from 2";
}
test3())(
echo "Hello World from 3";
}

Now let's create a script that will use our functions. You can import the library using the source command or simply by specifying the script name:

!/bin/bash
source lib.sh
test1
test2
test3

conclusions

In this article, we looked at bash functions, how to write them, use them, and combine them into libraries. If you often write scripts in Bash, then this information will be useful to you. You can create your own set of functions to use in each script and thereby make your work easier.

getopts is a Bash built-in command used to parse arguments passed to a script from the command line. It allows you to process a series of options combined into a single argument and additional arguments passed by the option.

# script_name -abc -d /home/user

The getopts command uses hidden variables: $OPTIND and $OPTARG.

A colon following an option name indicates that it has an additional argument.

While getopts ":abcde:fg" Option

Typically getopts is packaged in a while loop, each pass of the loop fetching the next option and its argument (if any), processing it, then decrementing the hidden variable $OPTIND by 1 and moving on to the beginning of a new iteration.

Options passed to a script from the command line must be preceded by a minus (-) or plus (+) character. This prefix (- or +) allows getopts to distinguish options from other arguments. In fact, getopts will not process arguments unless they are preceded by a - or + character; option selection will stop as soon as the first argument is encountered.

A typical while loop design with getopts differs slightly from the standard one due to the absence of square brackets to check whether the loop continues.
You can see how getopts works using the following script.

test-getopts

usage() (
echo "The script `basename $0` is intended to demonstrate the capabilities of getopts."
echo ""
echo "Usage: `basename $0` -abef -c C -d D"
echo -e » \033 # Script called without arguments?
then
usage # If launched without arguments, display help
exit $E_OPTERROR # and exit with error code
fi

while getopts "abc:d:ef" Option
do
case $Option in
a | b) echo "Action 1: option - $Option. Option number: $OPTIND. Argument: $OPTARG";;
c) echo "Action 2: option - $Option. Option number: $OPTIND. Argument: $OPTARG";;
d) echo "Action 3: option - $Option. Option number: $OPTIND. Argument: $OPTARG";;
e) echo "Action 4: option - $Option. Option number: $OPTIND. Argument: $OPTARG";;
f) echo "Action 5: option - $Option. Option number: $OPTIND. Argument: $OPTARG";;
*) echo "Invalid key selected."
usage
exit $E_OPTERROR;; # DEFAULT
esac
done
shift $(($OPTIND - 1))

Try running it like this:

Test-getopts -abc с-opt
test-getopts -abefd d-opt

And now like this:

Test-getopts -abcdef
test-getopts -cd d-opt

This behavior of getopts is due to the fact that the -c option expects an additional argument.

Having mastered the previous parts of this series of materials, you learned about what bash scripts are, how to write them, how to control the flow of program execution, and how to work with files. Today we will talk about how to add interactivity to scripts by equipping them with the ability to receive data from the user and process this data.

The most common way to pass data to scripts is by using command line parameters. By calling the script with parameters, we pass it some information with which it can work. It looks like this:

$ ./myscript 10 20
In this example, two parameters are passed to the script - “10” and “20”. All this is good, but how to read the data in the script?

Reading Command Line Options

The bash shell assigns special variables called positional parameters to the command line parameters entered when calling the script:
  • $0 - script name.
  • $1 is the first parameter.
  • $2 is the second parameter - and so on, up to the variable $9, which contains the ninth parameter.
Here's how to use command line options in a script using these variables:

#!/bin/bash echo $0 echo $1 echo $2 echo $3
Let's run the script with the parameters:

./myscript 5 10 15
This is what it will output to the console.


Displaying the parameters with which the script was launched

Note that command line options are separated by spaces.

Let's look at another example of using parameters. Here we will find the sum of the numbers passed to the script:

#!/bin/bash total=$[ $1 + $2 ] echo The first parameter is $1. echo The second parameter is $2. echo The sum is $total.
Let's run the script and check the result of the calculations.


Script that finds the sum of numbers given to it

Command line options do not have to be numbers. You can also pass strings to scripts. For example, here is a script that works with the string:

#!/bin/bash echo Hello $1, how do you do
Let's run it:

./myscript Adam
He will output what we expect from him.


Script working with string parameter

What if the parameter contains spaces and we need to treat it as a separate piece of data? We believe that if you have mastered the previous parts of this guide, you already know the answer. It involves using quotation marks.

If the script needs more than nine parameters, when accessing them, the number in the variable name must be enclosed in curly braces, for example like this:

Checking parameters

If the script is called without parameters, but their presence is assumed for normal operation of the code, an error will occur. Therefore, it is recommended to always check for the presence of parameters passed to the script when called. For example, it can be organized like this:

#!/bin/bash if [ -n "$1" ] then echo Hello $1. else echo "No parameters found." fi
Let's call the script first with a parameter, and then without parameters.


Calling a script that checks for the presence of command line parameters

Calculation of parameters

In a script, you can count the number of parameters passed to it. The bash shell provides a special variable for this. Specifically, the $# variable contains the number of parameters passed to the script when called.

Let's try it:

#!/bin/bash echo There were $# parameters passed.
Let's call the script.

./myscript 1 2 3 4 5
As a result, the script will report that 5 parameters were passed to it.


Counting the number of parameters in a script

This variable provides an unusual way to obtain the last parameter passed to the script, without requiring knowledge of their number. This is what it looks like:

#!/bin/bash echo The last parameter was $(!#)
Let's call the script and see what it outputs.


Accessing the last parameter

Capture all command line options

In some cases, you need to capture all the parameters passed to the script. To do this, you can use the variables $* and $@ . They both contain all the command line parameters, making it possible to access what is passed to the script without using positional parameters.

The $* variable contains all the parameters entered on the command line as a single “word”.

In the $@ variable, the parameters are broken down into individual “words”. These parameters can be iterated in loops.

Let's look at the difference between these variables using examples. First, let's take a look at their contents:

#!/bin/bash echo "Using the \$* method: $*" echo "-----------" echo "Using the \$@ method: $@"
Here is the output of the script.


Variables $* and $@

As you can see, when outputting both variables, the same thing is obtained. Now let's try to go through the contents of these variables in loops in order to see the difference between them:

#!/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
Take a look at what the script outputs to the console. The difference between the variables is quite obvious.


Parsing $* and $@ variables in a loop

The $* variable contains all the parameters passed to the script as a single piece of data, while in the $@ variable they are represented as independent values. Which variable to use depends on what exactly is needed in a particular scenario.

shift command

The shift command should be used with caution in bash scripts, as it literally shifts the values ​​of positional parameters.

When you use this command, it, by default, shifts the positional parameter values ​​to the left. For example, the value of the variable $3 becomes the value of the variable $2, the value of $2 goes to $1, and what was previously in $1 is lost. Please note that the value of the $0 variable containing the script name does not change.

Using the shift command, let's consider another way to iterate through the parameters passed to the script:

#!/bin/bash count=1 while [ -n "$1" ] do echo "Parameter #$count = $1" count=$(($count + 1)) shift done
The script uses a while loop, checking the length of the first parameter value. When the length becomes zero, the loop exits. After checking the first parameter and displaying it on the screen, the shift command is called, which shifts the parameter values ​​​​by one position.


Using the shift command to cycle through options

When using the shift command, remember that each time it is called, the value of the $1 variable is permanently lost.

Command line switches

Command line switches usually look like letters preceded by a dash. They serve to manage scripts. Consider this example:

#!/bin/bash echo 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" ;; *) echo "$1 is not an option" ;; esac shift done
Let's run the script:

$ ./myscript –a –b –c –d
And let's analyze what it outputs to the terminal.


Handling keys in a script

This code uses a case construct that checks the key passed to it with the list of keys processed by the script. If the passed value is found in this list, the corresponding branch of code is executed. If, when calling the script, any key is used, the processing of which is not provided, the “*” branch will be executed.

How to distinguish between keys and parameters

Often when writing bash scripts, a situation arises when you need to use both command line parameters and switches. The standard way to do this is to use a special sequence of characters that tells the script when the keys end and normal parameters begin.

This sequence is a double dash (--). The shell uses it to indicate the position at which the list of keys ends. After the script detects a sign of the end of keys, what remains can, without fear of errors, be processed as parameters, and not as keys. Let's look at an example:

#!/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 done count=1 for param in $@ do echo "Parameter #$count: $param" count=$(($count + 1)) done
This script uses the break command to break the while loop when it encounters a double dash in a line.

This is what happens after calling him.


Handling Command Line Switches and Parameters

As you can see, when the script, parsing the data passed to it, finds a double dash, it completes processing the keys and considers everything that has not yet been processed as parameters.

Handling keys with values

As your scripts become more complex, you will encounter situations where regular keys are no longer sufficient, which means you will need to use keys with some kind of value. For example, calling a script that uses this feature looks like this:

./myscript -a test1 -b -c test2
The script must be able to detect when additional parameters are used along with command line switches:

#!/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 echo "Parameter #$count: $param" count=$(($count + 1)) done
Let's call this script like this:

./myscript -a -b test1 -d
Let's look at the results of his work.


Processing key parameters

In this example, three keys are processed in the case construct. The -b switch requires an additional parameter. Since the key being processed is in the variable $1, the corresponding parameter will be in $2 (the shift command is used here, so as it is processed, everything passed to the script is shifted to the left). When we figured this out, all that remains is to extract the value of the $2 variable and we will have the parameter of the desired key. Of course, we'll need another shift command here to get the next key into $1 .

Using standard keys

When writing bash scripts, you can choose any letters for command line switches and arbitrarily set the script's reaction to these keys. However, in the Linux world, the meanings of certain keys have become something of a standard that is useful to adhere to. Here is a list of these keys:
-a Print all objects.
-c Perform the calculation.
-d Specify directory.
-e Expand the object.
-f Specify the file from which to read data.
-h Display help for the command.
-i Ignore case.
-l Execute full-format data output.
-n Use non-interactive (batch) mode.
-o Allows you to specify the file to which you want to redirect the output.
-q Execute the script in quiet mode.
-r Process folders and files recursively.
-s Execute the script in silent mode.
-v Perform verbose output.
-x Exclude object.
-y Answer “yes” to all questions.

If you work on Linux, you are likely familiar with many of these switches. By using them in their common sense in your scripts, you can help users interact with them without having to worry about reading the documentation.

Receiving data from the user

Command line switches and parameters are a great way to get data from the person using the script, but in some cases you need more interactivity.

Sometimes scripts need data that the user must enter while the program is running. The bash shell has a read command for precisely this purpose.

This command allows you to accept input either from standard input (keyboard) or using other file descriptors. After receiving the data, this command places it in a variable:

#!/bin/bash echo -n "Enter your name: " read name echo "Hello $name, welcome to my program."
Note that the echo command that displays the prompt is called with the -n switch. This causes the line feed to not appear at the end of the prompt, allowing the script user to enter data where the prompt is located rather than on the next line.


Handling user input

When calling read, you can specify multiple variables:

#!/bin/bash read -p "Enter your name: " first last echo "Your data for $last, $first..."
This is what the script will output after running.


Multiple variables in read command

If you call read without specifying a variable, the user's input will be placed in the special REPLY environment variable:

#!/bin/bash read -p "Enter your name: " echo Hello $REPLY, welcome to my program.


Using the REPLY environment variable

If the script must continue execution regardless of whether the user enters some data or not, when calling the read command, you can use the -t switch. Namely, the key parameter specifies the input wait time in seconds:

#!/bin/bash if read -t 5 -p "Enter your name: " name then echo "Hello $name, welcome to my script" else echo "Sorry, too slow! " fi
If no data is entered within 5 seconds, the script will execute the else branch of the conditional statement, printing an apology.


Time limit for data entry

Entering passwords

Sometimes what the user enters in response to a script question is best not shown on the screen. For example, this is usually done when asking for passwords. The -s switch to the read command prevents keyboard input from being displayed on the screen. In fact, the data is output, but the read command makes the text color the same as the background color.

#!/bin/bash read -s -p "Enter your password: " pass echo "Is your password really $pass?"
Here's how this script will work.


Entering sensitive data

Reading data from a file

The read command can, each time it is called, read one line of text from a file. When there are no more unread lines left in the file, it will simply stop. If you need to get the entire contents of a file in a script, you can, using a pipeline, pass the results of calling the cat command on the file to the while construct, which contains the read command (of course, using the cat command looks primitive, but our goal is to show everything as simply as possible, focusing on beginners; experienced users will surely understand this).

Let's write a script that uses the approach we just described to reading files.

#!/bin/bash count=1 cat myfile | while read line do echo "Line $count: $line" count=$(($count + 1)) done echo "Finished"
Let's look at him in action.


Reading data from a file

Here we passed the contents of the file into the while loop and iterated through all the lines of this file, displaying the number and contents of each of them.

Results

Today we looked at working with command line switches and parameters. Without these tools, the range of use of scripts is extremely narrow. Even if the script is written, as they say, “for yourself.” Here we also looked at approaches to obtaining data from the user during program execution - this makes scripts interactive.

Next time we'll talk about input and output operations.

Dear readers! Thank you for sharing your experience in the comments to the previous parts of this series of materials. If you have something to say about handling everything that can be passed into a script at startup or while it is running, we are sure that many people will be interested in reading about it.

Internet