DEV Community

taijidude
taijidude

Posted on • Edited on

TIL: Slightly over engineered (😅) text replace function (sed multiple replacements)

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

}
Enter fullscreen mode Exit fullscreen mode

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.
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode
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.
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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"
Enter fullscreen mode Exit fullscreen mode

The result is:

$ ./test456.sh
Hello from the ltest function!
-->
Enter fullscreen mode Exit fullscreen mode

unset: With this keyword you are able to clear previously set variables.

test="Hello!";
echo "-->$test"
unset test
echo "-->$test"
Enter fullscreen mode Exit fullscreen mode

The result is:

$ ./test456.sh
-->Hello!
-->
Enter fullscreen mode Exit fullscreen mode

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.  
Enter fullscreen mode Exit fullscreen mode

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 "$@";
Enter fullscreen mode Exit fullscreen mode

The result:

$ ./test456.sh 1 2 3
1 2 3
2 3
3
Enter fullscreen mode Exit fullscreen mode

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.

Top comments (0)