Skip to main content

% 16k.es

Bash strings

Table of Contents

Sometimes we face certain limitations when writing shell scripts when handling strings, and we often forget that bash has a lot of strings operators.

bash

Por example:

# Example string:
string=123.abc.456.ABC.123

# string length
$ echo ${#string}
19

# extract substring from a position
$ echo ${string:4}
abc.456.ABC.123

# extract substring from a position
# to a particular length
$ echo ${string:4:7}
abc.456

# Remove the matching string from the beginning
$ echo ${string#123}
.abc.456.ABC.123

# Remove the matching string from the end
$ echo ${string%123}
123.abc.456.ABC.

# Replace the first occurrence of a substring
$ echo ${string/123/QWE}
QWE.abc.456.ABC.123

# Replace all occurrences of a substring
$ echo ${string//123/QWE}
QWE.abc.456.ABC.QWE

# Replace the first occurrence of a substring at the beginning...:
$ echo ${string/#123/QWE}
QWE.abc.456.ABC.123

# ...or at the end
$ echo ${string/%123/QWE}
123.abc.456.ABC.QWE

# Length of the match at the beginning of the string (two different ways)
$ expr match "$string" '123'
3
$ expr "$string" : '123'
3

# String comparison

Another point where it is not difficult to make mistakes is in comparisons; since bash is not a typed language, certain constructions can lead to errors that go unnoticed and become very difficult to detect. So let’s remember:

Compare operator is =, not -eq.

Examples:

$ $a=foo
$ $b=bar
$ [ "$a" = "$b" ] && echo 'the two variables are equal' || echo 'the two variables are different'
the two variables are different

$ [ "$a"="$b" ] && echo 'the two variables are equal' || echo 'the two variables are different'
the two variables are equak

== is a synonym of =

$ [ "$a" == "$b" ] && echo 'the two variables are equal' || echo 'the two variables are different'
the two variables are different

“not equal” operator is !=

$ if [ "$a" != "$b" ]; then echo "the two variables are different"; fi
the two variables are different

Pero, con dobles corchetes, el funcionamiento es distinto (pattern matching):

$ filename=foto.jpg
$ if [[ "$filename" != *.gif ]]; then echo "the file is not a gif"; fi
the file is not a gif

If the expressions are complex, the operators -a (logical and) and -o (logical or) can be used. And, only in the case of double brackets, their ‘almost’ equivalents && and ||

$ if [ "$a" = "foo" -a "$b" = "bar" ]; then echo "foobar"; fi
$ if [[ "$a" == "foo" && "$b" == "bar" ]]; then echo "foobar"; fi