By: Daniel Farina | Updated: 2019-01-15 | Comments | Related: > SQL Server on Linux
Problem
We will continue our tip series on Bash scripting that can be used when working with Linux and SQL Server running on Linux. In this tip we will cover parameter expansions.
Solution
On most of my previous tips about Bash Scripting I was using expansions without let you know. Only in the tip about functions in Bash Scripting I let you know I was using Arithmetic Expansions. Parameter expansions are a very powerful tool in scripting as well as in the day to day bash console usage. By using expansions you can define ranges, create enumerations, concatenate and subtract text data. Let's learn more about how they can be used.
Parameter Types
First I have to clarify that on Linux the term Parameter is used to describe entities that store values like arrays and variables. In other words, a parameter is not limited to the argument of a command and you can refer to a variable as a parameter too even if it is not ever used as part of a command argument. The reason behind this is that Bash distinguishes between three types of parameters: positional parameters, special parameters, and variables.
Positional Parameters
A positional parameter is denoted by one or more digits distinct to zero. Positional parameters are assigned from the arguments of a command or function when it is invoked, and may be reassigned using the set built-in command. You can refer to the positional parameter 7 as $7 or ${7}. When a positional parameter consisting of more than a single digit is expanded, it must be enclosed in braces.
Special Parameters
These are predefined parameters that have a special meaning for Bash. These parameters are read only so you cannot change them.
This table lists the special parameters and gives a description of each.
Parameter | Description |
---|---|
$* | It expands to all positional parameters as one sentence. In layman terms, it writes the positional parameters separated by space. |
$@ | Almost identical than $*. |
$# | It returns the number of positional parameters. |
$? | Returns the exit status of the previous command. |
$- | Prints the current options flags. You can modify option flags with the set command. |
$$ | Returns the process ID (PID) of the shell. |
$! | Returns the process ID (PID) of the last executed background task. |
$0 | It returns the name of the shell script, or when executed in the console, the name of the current shell. |
$_ | Shows the previous command being executed. |
Take a look at the next script were I show how to use the $*, $@, $# and $? parameters.
#!/bin/bash echo "Number of Arguments: $#" echo "All Arguments with \$*: $*" echo "All Arguments with \$@: $@" echo echo "First Argument: $1" echo "Second Argument: $2" echo "Third Argument: $3" echo "Fourth Argument: $4"
On the screen capture below, you will see the result of executing the above script. Notice that in order to show the behavior of the $? expansion I wrote it straight in the shell after running the script.
#This is to be run in the console ./sample.sh arg1 arg2 arg3 echo "$?" # this will return zero (no error) blah #This command doesn't exists, therefore will return nonzero (error)
By running echo "$?" I am querying the exit status of the last executed command. In the previous screen capture you can see that echoing the $? expansion after the execution of the script the output is zero which means that the previous command exited with an exit condition equal to zero which is the de facto when there is no errors. Alternatively you can see that when I echo the $? expansion before running a non-existing command I get a nonzero result which indicates that there was an error on the previous command.
Let's consider the next script where I use the $- expansion to display the current option flags, show the current process id with the $$ expansion and also I display the actual script name making use of the $0 expansion.
#!/bin/bash echo "Before Setting a Flag..." echo "$-" echo "Setting a Flag..." set -b echo "$-" echo "(PID) of the shell" $$ echo "Print \$0 : " $0
As you can see on the previous image, the result of echoing the $- expansion changes from "hB" after we set the –a flag which is used to export all the variables defined after we set it to "ahB".
Parameter Expansion Modifiers, Brace Expansions?
By now you know that in order to expand a parameter you have to put a dollar sign in front of it or put the parameter into braces with a dollar sign in front of it. But also there are operators that can be used in the braces that modify the expansion.
We have the chance to use brace expansion to generate a combination of strings, take a look at the following code.
#!/bin/bash var="Exp" echo ${var}{"ansion","ense"} ls /home/{daniel,test}t3
On the previous script you can see that I created a variable "var" with the string "Exp" and I concatenated that variable with a set of two words ("ansion","ense") that allowed me to echo the words "Expansion" and "Expense". Additionally you will see a practical example on how to use it to concatenate a root folder with two subfolders and list the files of those folders.
Expanding Ranges
If you remember from my tip about iterative statements on Bash you have already seen how parameter expansions deal with ranges. But if you don't remember don't worry, I will explain it again.
You can define a range as {a..b} where a and b can be either numbers or characters. This is the easiest way to define sets or arrays.
Take a look at the next example when I define a range from "a" to "z" and another from 0 to 9. Additionally I created a For Loop that echoes statements to copy a set of files to show you a case of use of range expansions.
#!/bin/bash a=a b=z eval echo {$a..$b} a=1 b=10 eval echo {$a..$b} for i in $(eval echo {$a..$b}); do echo "cp file_"$i".bak /backup" done
On the next screen capture you will see the results of executing the previous script.
Now I will show you how you can use expanding ranges to print all numbers that can be represented in a byte in hexadecimal format. Additionally the next script shows how to declare an array variable containing a range expansion and how to access a specific item in that array.
#!/bin/bash echo {{0..9},{A..F}}{{0..9},{A..F}} declare -a MyArray=({{0..9},{A..F}}{{0..9},{A..F}}) read -p "Enter a decimal number from 0 to 255: " Position echo Number $Position is Hex ${MyArray[$Position]}
The next screen capture shows the execution of the previous script.
String Case Modification with Parameter Expansions
There are operators we can use inside a parameter expansion to change the case of a string variable (scalar or array).
Expansion | Usage | Description |
---|---|---|
^ | ${Parameter^} | Changes to uppercase the first letter of Parameter. |
^^ | ${Parameter^^} | Changes to uppercase all letters of Parameter. |
, | ${Parameter,} | Changes to lowercase the first letter of Parameter. |
,, | ${Parameter,,} | Changes to lowercase all letters of Parameter. |
~ | ${Parameter~} | Reverse the case of the first letter of Parameter. |
~~ | ${Parameter~~} | Reverse the case of all letters of Parameter. |
I created the following script to show these expansions in action.
#!/bin/bash Parameter="hello World" echo "\$Parameter " $Parameter echo "\${Parameter^}" ${Parameter^} echo "\${Parameter^}" ${Parameter^^} echo -e "\nassign Parameter=\${Parameter^}" Parameter=${Parameter^} echo "\$Parameter " $Parameter echo "\${Parameter,}" ${Parameter,} echo "\${Parameter,,}" ${Parameter,,} echo "\${Parameter~}" ${Parameter~} echo "\${Parameter~~}" ${Parameter~~}
On the next image you can see the execution of the previous script.
Handling Substrings with Parameter Expansions
When working with Bash scripts you don't need to use complex functions to deal with strings variables and create substrings. You only need to separate with a colon (:) the offset and the length.
${Parameter:Offset:Length}
- Parameter: is any string variable or array.
- Offset: specifies where the returned characters start. The numbering is zero based and counts from left to right when the number is positive and from right to left when the number is negative. Keep in mind that if you use a negative number you have to put it between round brackets.
- Length: specifies how many characters of Parameter will be returned. This is optional, but if it is omitted the expansion will be from Offset to the end of Parameter.
Let's take a look at the next script as an example.
#!/bin/bash Parameter="Hello World" echo ${Parameter:6} echo ${Parameter:0:5} echo ${Parameter:0:5} echo ${Parameter:(-5):5}
On the next screen capture you will see the results of executing the previous script.
Search and Replace on String Parameters
There is an expansion that we can use for search and replace inside parameters. We must add a slash (/) at the end of the parameter to be expanded and specify the pattern to search. In case we also want to replace the searched pattern with a string we must add a slash (/) at the end to pattern to be search and replaced.
${Parameter/Pattern/Replacement}
- Parameter: is any string variable or array.
- Pattern: is the string containing the pattern to be searched.
- Replacement: contains the text to use as replacement when Pattern is found.
Something important to remark is that the replacement won't change the value of the parameter. The expansions never change the parameter itself, they only change the way it is being returned or showed.
In case you want to search and replace all the occurrences of a pattern you must use a double slash (//) at the end of the parameter.
The next script shows an example on those concepts.
#!/bin/bash Parameter="Hello World" echo ${Parameter/el} echo ${Parameter/el/x} echo $Parameter echo ${Parameter//o} echo ${Parameter//o/x} echo $Parameter
On the next screen capture you will see the results of executing the previous script.
Suffix and Prefix Removal with Parameter Expansions
There are also parameter expansions that allow us to remove the starting part (suffix) or the bottom part (prefix) of a string parameter according to a given pattern. It is like the LEFT and RIGHT functions in SQL Server. This is useful for example when you need to change the extension of a file.
Expansion | Usage | Description |
---|---|---|
# | ${Parameter#Pattern} | Removes from Parameter the Pattern from the first match starting from the beginning of parameter. |
## | ${Parameter##Pattern} | Removes from Parameter the Pattern from the last match starting from the beginning of parameter. |
% | ${Parameter%Pattern} | Removes from Parameter the Pattern from the first match starting from the end of parameter. |
%% | ${Parameter%%Pattern} | Removes from Parameter the Pattern from the last match starting from the end of parameter. |
The next script illustrates the usage of those expansions.
#!/bin/bash Parameter="Hello World" echo ${Parameter#*o} echo ${Parameter##*o} echo $Parameter echo ${Parameter%o*} echo ${Parameter%%o*} echo $Parameter
On the following screen capture you can see the execution results of the previous script.
String Length of a Parameter
If you need to count the length of a string parameter you can use the following expansion using the # sign in front of the parameter. This expansion is very useful when you are using the ":" expansion to handle substrings.
${#Parameter}
Take a look at the next script when I show you how to count the number of characters in a parameter.
#!/bin/bash Parameter="Hello World" echo ${#Parameter}
On the following screen capture you can see the results of the execution of the previous script.
Next Steps
- Stay tuned for the next tips in this series.
- If you haven't read the first tip of this series you can do do so here Introduction to Bash Scripting for SQL Server DBAs
- Are you new to SQL Server running on Linux? You should read this tip: Getting Started with SQL Server on Linux
- Are you a SQL Server DBA new to Linux? Here you will find 7 Things Every SQL Server DBA Should Know About Linux
- In this tip you will find the Top 10 Linux Commands for SQL Server DBAs
- For more, take a look at the SQL Server on Linux Tips Category
About the author
This author pledges the content of this article is based on professional experience and not AI generated.
View all my tips
Article Last Updated: 2019-01-15