I recently had to read a lot of long bash scripts. Stumbled about a few things I found interesting and played a little with them. I will explain them later. But first behold the mighty text replace function i created will played around.
function repl {
if [[ "$#" -eq 0 ]]; then
echo "[ERROR]The parameter list needs at least 3 items. The file to work with, the string to replace and the new string! ";
return
fi
local file="$1";
if ! [[ -f "$file" ]]; then
echo "[ERROR]The $file doesn't exists!";
return
fi
shift;
if [[ "$#" -eq 0 ]]; then
echo "[ERROR]No parameters except the file found!";
return
fi
if [[ $(expr "$#" % 2 ) -eq 1 ]]; then
echo "[ERROR]Invalid Amount of parameters after the filename!"
return
fi
old=""
new=""
replacements=""
for item in "$@"
do
if [[ -z "$old" ]];
then
old=$item;
elif [[ -n "$old" ]] && [[ -z "$new" ]]
then
new=$item;
fi
if [[ -n "$old" ]] && [[ -n "$new" ]]
then
replacements="s/$old/$new/g; "
sed -i "$replacements" $file
unset old;
unset new;
fi
done
}
It's a convenient wrapper function around a sed call to edit a file. For an example let's assume we have the following data file.
The Republic is in control of this planet now.
A Jedi will arrive shortly to solve the most important problems.
The local ewok tribes will be rescued.
This file needs a few corrections. In the bash shell normally sed can be used to edit this file in place.
sed -i s/Republic/Empire/g StarWars.txt
sed -i s/Jedi/Inquisitor/g StarWars.txt
sed -i s/rescued/murdered/g StarWars.txt
cat StarWars.txt
The Empire is in control of this planet now.
A Inquisitor will arrive shortly to solve the most important problems.
The local ewok tribes will be murdered.
Ah, that's better. 😉
You can even write this in one line.
sed -i s/Republic/Empire/g; s/Jedi/Inquisitor/g; s/rescued/murdered/g; StarWars.txt
After this discovering this, i relealized i might not need my function at all. But as an excersis it was nice and i learned a few things.
So how does a call of my function look?
repl StarWars.txt Republic Empire Jedi Inquisitor rescued murdered
It's a little bit less verbose. And provides a little bit of additional error handling. But I need to check out sed's error handling. Maybe I can throw out my custom error handling.
One big takeaway from this (again): What are you trying to do has likely been done before and there likely is a solution for this.
But anyway, What else did I learn?
local: If you put the local keyword in front of a variable. The variable is only visible in the block of code where it is declared.
function ltest {
local test="Hello from the ltest function!";
echo "$test"
}
ltest
echo "-->$test"
The result is:
$ ./test456.sh
Hello from the ltest function!
-->
unset: With this keyword you are able to clear previously set variables.
test="Hello!";
echo "-->$test"
unset test
echo "-->$test"
The result is:
$ ./test456.sh
-->Hello!
-->
test command: To test specific conditions for if statement bash has the test command. With this tool you are able to check file attributes and to string and number comparisons. It doesn't has output. But if it exits with a with 0 that means the supplied expression is true. A 1 stands for false.
test 1 -lt 2 && echo "true"
# There is an shortcut to write this
[ 1 -lt 2 ] && echo "true"
# You will see a third way of writing this.
[[ 1 -lt 2]] && echo "true"
# This will run another test command that bash has adopted from the kornshell.
The kornshell test command seems to offer more functionality and the general recommendation seems to be to use it instead of the bash one.
shift: This shifts every parameter in you function to the left and puts every parameter in a lower position. The first parameter gets dropped.
echo "$@";
shift;
echo "$@";
shift;
echo "$@";
The result:
$ ./test456.sh 1 2 3
1 2 3
2 3
3
exit/return: To abort a script you can use the exit keyword. But this will close the shell window as well. If you don't want the window to close, just use the return keyword.