Introduction to Bash Scripting: Parameter Expansions

By:   |   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)
Using special parameters in Bash.

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
Setting flags in bash.

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.

This is a brace expansions.

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.

Using range expansion to copy files.

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.

Creating an Array with range expansions.

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.

Changing case of strings using parameter expansions.

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.

Splitting strings using parameter expansions.

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.

Searching and replacing using parameter expansions.

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.

Removing characters from the start or the end of a string using parameter expansions.

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.

Getting the lenght of a string parameter.
Next Steps


sql server categories

sql server webinars

subscribe to mssqltips

sql server tutorials

sql server white papers

next tip



About the author
MSSQLTips author Daniel Farina Daniel Farina was born in Buenos Aires, Argentina. Self-educated, since childhood he showed a passion for learning.

This author pledges the content of this article is based on professional experience and not AI generated.

View all my tips



Comments For This Article

















get free sql tips
agree to terms