Windows.  Viruses.  Laptops.  Internet.  Office.  Utilities.  Drivers

When writing scripts in Bash, not only experienced programmers, but also those new to the Bash shell are faced with working with strings. This is most often necessary when reading commands entered by the user as arguments to an executable script, as well as when processing text files. And one of the necessary techniques in this case is string comparison.

This article will look at comparing Bash strings, as well as some nuances on using comparison operations and solving common errors.

These operations allow you to determine whether the strings being compared are the same:

  • = - equal, for example if [ "$x" = "$y" ]
  • == - a synonym for the "=" operator, for example if [ "$x" == "$y" ]
  • != - not equal, for example if [ "$x" != "$y" ]

#!/bin/bash
testuser=anton
if [ $USER = $testuser ]
then
echo "Welcome $testuser"
fi

The result of the script:

When testing for equality using the command test(synonymous with square brackets) all punctuation marks and differences in the case of letters of the compared strings are taken into account.

Some features of string comparison with patterns:

# returns true if the string contained in $x begins with the character "y"
[[ $x == y* ]]
# returns true if the string from $x is equal to exactly two characters "y*"
[[ $x == "y*" ]]
# returns true if $x contains the name of a file contained in the current directory that begins with "y"
[ $x == y* ]
# returns true if string $x equals two "y*" characters
[ "$x" == "y*" ]

For example, checking a bash string to see if it starts with the character y:

#!/bin/bash
x=yandex
[[ $x == y* ]]
echo $?

Result of executing the code:

The script output 0 (zero) because we requested the error code of the last executed instruction to be displayed. And code 0 means that the script was executed without errors. And indeed - a variable $x contains the string yandex, which begins with the character "y". Otherwise, "1" may be written. It's pretty convenient way debugging scripts.

Comparing strings alphabetically in Bash

The task becomes more difficult when trying to determine whether a row is a predecessor of another row in an ascending sort sequence. People writing bash scripts often run into two problems regarding the greater than and less than operators relative to Linux string comparisons, which have fairly simple solutions:

First, the greater-than and less-than characters need to be escaped by preceding them with a backslash (\), because otherwise the shell will treat them as redirection characters and the strings as file names. This is one of those cases where it is quite difficult to track down the error.

#!/bin/bash
# incorrect use of string comparison operators
val1=baseball
val2=hockey
if [ $val1 > $val2 ]
then

else

fi

What do you get if you compare the bash strings:

As you can see, the “greater than” symbol alone in its immediate form led to incorrect results, although no errors were generated. IN in this case this character caused the output stream to be redirected, so no syntax errors were detected and, as a result, a file called hockey:

To resolve this error, you need to escape the ">" character so that the condition looks like this:

...
if [ $val1 \> $val2 ]
...

Then the result of the program will be correct:

Secondly, strings ordered using the greater than and less than operators are arranged differently than with the command sort. Here, problems are more difficult to recognize, and you may not encounter them at all if the comparison does not take into account the case of letters. In a team sort And test comparison occurs in different ways:

#!/bin/bash
val1=Testing
val2=testing
if [ $val1 \> $val2 ]
then
echo "$val1 is greater than $val2"
else
echo "$val1 is less than $val2"
fi

Result of the code:

In a team test lines with uppercase letters will first precede lines with lowercase letters. But if you write the same data to a file, to which you then apply the command sort, then lines with lowercase letters will come first:

The difference between their work is that in test To determine the sort order, the arrangement of characters in the ASCII table is taken as a basis. IN sort The sort order specified for the locale settings is used.

Checking a string for empty value

Comparison using operators -z And -n used to determine whether a variable contains contents. This way you can find bash empty lines. Example:

#!/bin/bash
val1=testing
val2=""
# checks if the string is empty
if [ -n $val1 ]
then
echo "The string "$val1" is not empty"
else
echo "The string "$val1" is empty"
fi
# checks if the string is empty
if [ -z $val2 ]
then
echo "The string "$val2" is empty"
else
echo "The string "$val2" is not empty"
fi
if [ -z $val3 ]
then
echo "The string "$val3" is empty"
else
echo "The string "$val3" is not empty"
fi

Result of the code:

This example creates two string variables - val1 And val2. Operation -n determines whether a variable has val1 non-zero length, and -z checks val2 And val3 to zero. It is noteworthy that the latter was not defined until the moment of comparison, but the interpreter believes that its length is still equal to zero. This nuance should be taken into account when various checks scenarios. And, if you are not sure what value is contained in the variable and whether it is set at all, it is worth checking it using the operator -n or -z and only then use it for its intended purpose.

It is worth paying attention to the function -n. If an undeclared or empty variable is passed to it for testing, it will return true rather than false. For such cases, you should enclose the string (variable) being checked in double quotes so it looks like this:

...
if [ -n "$val1" ]
...

conclusions

There are certain nuances to the presented Bash string comparison operations that are worth understanding to prevent script errors. But in practice there are many such situations, so it’s impossible to remember everything (let alone describe it).

In Bash shell scripts, we can perform number comparisons. To perform a number comparison operation in Bash, you must use the “test” state within an if or loop. In this post we will tell you how to compare numbers in bash.

Operators for Bash comparison of numbers

operatorwhat is he doingexample
-eqcompare numbers in bash for equality, returns 0 if equalif [ $a -eq $b ] then
-gecomparing numbers in bash if greater than or equal. Result returns 0 if greater than or equal toif [ $a -ge $b ] then
-gtcompares numbers in bash if greater.if [ $a -gt $b ] then
-leCompares numbers in bash if less than or equal.if [ $a -le $b ] then
-ltcompares numbers in bash if less.if [ $a -lt $b ] then
-necompares numbers in bash if not equal or not.if [ $a -ne $b ] then

Examples in detail of number comparison operators in Bash:

1. operator-eq

This operator compares numbers, will check the value is equal or not. If it is equal, then 0 is returned.

# cat test.sh #!/bin/bash echo "enter the value of the variable" read a echo "enter the value of the variable" read b if [ $a -eq $b ] then echo "Return value:: $?" echo "a and b are equal" else echo "Return value:: $?" echo "a and b are not equal" fi #

Execution:

# sh test.sh enter the value of variable 2 enter the value of variable 3 Return value:: 1 a and b are not equal # sh test.sh enter the value of variable 2 enter the value of variable 2 Return value:: 0 a and b are equal #

In the above example, we took the numbers 2 and 3 for the first time and the system returned the value 1, however, when we took the same values ​​for a and b, the variable returns a value of zero.

2. operator-ge

This operator compares numbers and tests whether the values ​​are greater than or equal to. If the value is greater than or equal to, then the return value is 0.

# cat test1.sh #!/bin/bash #compare program for -ge echo "enter the value of the variable" read a echo "enter the value for the variable b" read b if [ $a -ge $b ] then echo "return value: : $?" echo "a is greater than or equal to b" else echo "return value:: $?" echo "a is not greater than or equal to b" fi #

3. operator -gt

This number comparison operator will test the number to be greater. If the value is greater, then returns 0.

# cat test2.sh #!/bin/bash #comparison program for -gt b=100 echo "enter a value greater than 100" read a if [ $a -gt $b ] then echo "Very good" else echo "Not very good " fi

4. operator-le

This number comparison operator will test values ​​for less than or equal to. If it is less than or equal to, then the return value is 0.

#compare program for -le b=5 echo "enter a value less than or equal to 5" read a if [ $a -le $b ] then echo "all correct" else echo "incorrect" fi #

5. operator-lt

This number comparison operator will test values ​​for less than. If the number is less, then the return value is 0.

if-else condition used in BASH scripts Often. The condition itself has a somewhat strange appearance [[ condition ]]. Pay attention to the indentations. Without them, the condition will not work. Here's a list logical operators for the condition [[ ? ]]:

List of logical operators that
used for if-then-else-fi construction

#!/bin/bash if [[ $1 > 2 ]] then # if [[ ? ]] echo $1" is greater than 2" else # if does not match echo $1" is less than 2 or 2" fi

Some of you may find the equality operator -eq strange. Try using familiar operators >

Let's say you have a script and you need to verify the user. If the user is not root, the script will stop.

#!/bin/bash if [ "$(whoami)" != "root" ]; then echo "You do not have permission to run $0." exit 1; fi

Often you need to check a variable to see if it has a value. If there is nothing in the variable, then you can stop the script.

#!/bin/bash if [ -n "$num" ]; then "the variable has something and you can start another process" else echo "an empty variable, stop the script" exit 0; fi

If the variable is empty, then it can be filled.

#!/bin/bash if [ -z "$num" ]; then echo "variable is empty" num=1 else echo "num="$num fi

An empty variable can be assigned a default value. This entry is shorter than in the previous example.

#!/bin/bash # Write DEFAULT if arguments command line missing [ -z "$arg1" ] && arg1=DEFAULT echo $arg1

Comparing strings in Bash doesn't cause any problems until you try to compare two strings in a case-insensitive manner. I will give several options for solving the problem that I use myself. The peculiarity of these solutions is that they use only the built-in capabilities of the Bash shell.

To begin, I'll create two variables, str1 and str2, containing the strings to compare. These are the ones that will be used in the following code examples.

#!/bin/bash str1 = "String To Compare" str2 = "string to compare"

The first version of case-insensitive string comparison I want to propose uses shell option management using the shopt builtin command.

shopt -s nocasematch [[ $str1 == $str2 ]] && echo "match" || echo "not match" shopt -u nocasematch

The next version of case-insensitive string comparison is based on the principle of independently converting strings to a common case. This code variant works on Bash 4 and later. Use it for more early version Bash will throw an error.

So, to compare strings converted to lowercase, you can use the following code option.

[[ " $( str1 , ) " == " $( str2 , ) " ]] && echo "match" || echo "not match"

If you want to cast the compared strings to uppercase, then you can use the following code.

[[ " $( str1 ^^ ) " == " $( str2 ^^ ) " ]] && echo "match" || echo "not match"

As alternative option, conversion of strings to a single register can be performed at the time of declaring variables. To do this, use the shell builtin command declare .

To declare a variable containing lowercase text, use the following code.

#!/bin/bash declare -l str = "Camel Case String"

As a result of executing this code, the str variable will contain a lowercase string, despite the fact that the assigned string was written in camel case. You can change the case of a string already specified in a variable as follows.

#!/bin/bash str = "Camel Case String" declare -l str str = $str echo $str

To convert a string to uppercase, in the code example above, you should change the call to the declare command, using the -u switch instead of the -l switch.

Now, case-insensitive string comparison using the declare command can be done as follows.

declare -l str1_l = $str1 declare -l str2_l = $str2 [[ $str1_l == $str2_l ]] && echo "match" || echo "not match"

Any of the case-insensitive string comparison options discussed can be used when writing Bash scripts. Therefore, if you are using Bash version 4 or higher, you can choose the one you like best. If the Bash version is lower than 4, then you should use the first option by specifying the nocasematch option using the shopt shell built-in command.

This topic is the fourth topic in the “Bash Shell Language” series. He will talk about such control structures of the language as conditional statements. But before moving on to their description, it is necessary to dwell on some nuances that will make the consideration of the material below more understandable.
First, let's look at what a command list is. A command list is a single command, pipeline, or sequence of commands/pipes separated by one of the following operators: ";", "&&", "||", terminated by a semicolon.
; - operator of sequential execution of several commands. Each subsequent command begins to be executed only after the previous one has completed (it doesn’t matter whether it was successful or not);
&& - operator to execute a command only after the previous one has been successfully completed;
|| - the operator of executing a command only after the previous one has been executed incorrectly.
Code successful completion is 0, and the error one is not zero (depending on the type of error). This should not be confused with conventional programming languages, where 1 is analogous to true, and 0 is analogous to false.
Now we can begin to directly consider conditional statements.

case operator

The general syntax of the case statement is:

case value in
template1) list1;;
template2 | template3) list2;;
esac

The logical sequence of execution of the case statement:
a) the first pattern matching the value is searched;
b) if it is found, the corresponding list of commands is executed, ending with ";;";
c) control is transferred to the statements following the case construction.
The template and list are separated by the character ")". One list of commands can correspond to several conditions, then they must be separated by the “|” symbol.
In templates you can use the symbols “*”, “?”, “”, which were discussed in the second topic of the series. With their help, you can implement an instruction that acts as a default in a switch statement in languages ​​such as C, PHP.
Here's an example of using case:
echo -n "[Universal viewer] Specify the file name: "; read File case "$File" in *.jpg|*.gif|*.png) eog $File ;; *.pdf) evince $File ;; *.txt) less $File ;; *.html) firefox $File ;; /dev/*) echo "Well, these are scary files." ;; *) echo "Okay, okay - not so universal." echo "I'm not familiar with this type of file. I don't know how to view it." ;; esac
Another example of using the case construct:
echo "Error. Who should I send the message to?" echo "To the boss: b" echo "To colleagues: c" echo "To no one: any key" read answer case $answer in b|B) mail –s "error log" boss< error.log;; c|C) mail –s "Help! error log" –c denis nick < error.log;; *) echo "error"; exit;; esac

Conditional operator if

The general syntax of the if statement is:

if list1 then
list2

fi

Square brackets here indicate optional constructs. The logical sequence of execution of the case statement:
a) list1 is executed;
b) if it is executed without errors, list2 is executed. Otherwise, list3 is executed, and if it completes without errors, list4 is executed. If list3 also returns an error code, list5 is executed;
c) control is transferred to the operators following the if construct.
Here's an example of using if:
if grep -q Bash file then echo "The file contains at least one Bash word." fi
When if and then appear on the same line, the if and then constructs must end with a semicolon. For example:
$if [$? –ne 0 ]; then echo “Error”; fi
Now, knowing that it is possible to place if and then on the same line, let's rewrite the above example:
if grep -q Bash file; then echo "The file contains the word Bash." fi

The test statement and conditional expressions

In the above example, a condition check is used instead of parsing the exit code. Two forms of this test are equivalent: the built-in test command and [condition]. For example, to check the existence of a file you need to write:
test –e<файл>
or
[ -e<файл> ]
If square brackets are used, they must be separated from each other by a space, because "[" is the name of the command, and "]" is the required last argument to its completion.
If the condition is checked successfully, 0 is returned, and if false, error code 1 is returned.
The test command can check if a string is empty. A non-empty string results in exit code 0. Empty, respectively – 1. For example:
$test $USER; echo $? 0
The "" design is more universal compared to "". This is an extended version of the test command. Within this construct, no additional interpretation of file names is performed and arguments are not split into separate words, but substitution of parameters and commands is allowed. For example:
file=/etc/passwd if [[ -e $file ]] then echo “Password file found.” fi
The "" construction is preferable to "" as it will help avoid some logical errors. For example, the operators "&&", "||", "<" и ">" inside " " are perfectly acceptable, while inside " " generate error messages.
The "(())" construction allows you to evaluate arithmetic expressions within it. If the result of the calculation is zero, an error code is returned. A non-zero result of a calculation produces a return code of 0. That is, the exact opposite of the test and "" instructions discussed above.
The if statement allows for nested checks:
if echo "The next *if* is inside the first *if*." if [[ $comparison = "integer" ]] then ((a< b)) else [[ $a < $b ]] fi then echo "$a меньше $b" fi

Conditional expressions can be combined using ordinary logical operations:
! <выражение>– denial;
<выражение1>–a<выражение2>– logical AND;
<выражение1>–o<выражение2>– logical OR.

Elementary conditional expressions for files:
-e - the file exists;
-f - a regular file (not a directory or a device file);
-s - non-zero file size;
-d - file is a directory;
-b - the file is a block device (floppy, cdrom, etc.);
-c - the file is a character device (keyboard, modem, sound card and so on.);
-p - the file is a channel;
-h - the file is a symbolic link;
-L - the file is a symbolic link;
-S - file is a socket;
-t - the file is associated with the terminal device;
-r - the file is readable (to the user who launched the script);
-w - the file is writable (for the user who launched the script);
-x - the file is available for execution (to the user who launched the script);
-g - (sgid) flag for file or directory is set;
-u - (suid) flag for the file is set;
-k - sticky bit flag is set;
-O - ​​you are the owner of the file;
-G - you belong to the same group as the file;
-N - the file has been modified since the last read;
file1 -nt file2 – file1 is newer than file2;
file1 -ot file2 – file1 is older than file2;
file1 -ef file2 – file1 and file2 are “hard” links to the same file.

Elementary conditional expressions for comparing strings:
-z string – string length is 0;
-n string – string length is not equal to 0;
line1 == line2 – the lines match (similar to “=”);
line1 !== line2 – the lines do not match (similar to “!=”);
line1< строка2 – строка1 предшествует строке2 в лексикографическом порядке;
line1 > line2 – line1 follows line2 in lexicographical order.
An arithmetic conditional expression has the format:
argument1 operation argument2, where the arguments are integers and the following operations are allowed:
-eq – equal;
-ne – not equal;
-lt – less;
-le – less than or equal;
-gt – more;
-ge – greater than or equal to;
< - меньше (внутри двойных круглых скобок);
<= - меньше или равно (внутри двойных круглых скобок);
> - greater than (within double parentheses);
>= - greater than or equal to (within double parentheses).

Let's rewrite the previous example using an if statement:
echo "Error. Who should I send the message to?" echo "Boss: b" echo "Colleagues: c" echo "No one: any key" read answer if [ "$answer" == "b" –o "$answer" == "B" ]; then mail –s "error log" boss< error.log; elif [ "$answer" == "c" –o "$answer" == "C" ]; then mail –s "Help! error log" –c denis nick < error.log; else echo "error"; exit; fi

In the next topic I will continue to look at the control structures of the bash command interpreter. Namely, loop operators will be considered. And now I’m waiting for comments and criticism :).

UPD: Thanks to the user

If you notice an error, select a piece of text and press Ctrl+Enter
SHARE: