String comparison (Bash)
Detect an unset or null variable
Maybe:
- unset means that a variable name that has not been declared
- null means that a variable has not been assigned any value to it (including an empty value).
However, these distinctions aren't very useful, as I don't know how to detect the difference. They seem to be even more academic, as in literature I couldn't find this distinction.
Variables
i1="Hallo" i2="" declare i3 [[ -v i1 ]] && echo " true - i1" # True: Variable is set (may be empty) [[ -v i2 ]] && echo " true - i2" # True: Variable is set (may be empty) [[ -v i3 ]] && echo " true - i3" [[ -v i4 ]] && echo " true - i4"
Note that the variables don't include the $
symbol. Appearantly, it's about the variables themselves, not their content.
Copy of an unset variable
This may seem far fetched, but it's quite relevant (for me):
unset i1 i2 i3 i4 i1="hallo" i3=$i1 i4="" i5=$i2 [[ -v i1 ]] && echo " true - i1" # True: Variable is set (may be empty) [[ -v i2 ]] && echo " true - i2" # False: Variable is not declared and not set [[ -v i3 ]] && echo " true - i3" # True: Variable is set (may be empty) [[ -v i3 ]] && echo " true - i3" # True: Variable is set (may be empty) [[ -v i4 ]] && echo " true - i4" # True: Variable is set (may be empty) [[ -v i5 ]] && echo " true - i5" # False: A copy of an undeclared variable, is undeclared
How this is relevant to me: When going through an associative array of translations, the first step is often that I copy the entities to make-shift variables to make it easier to handle. However, when I do so, I loose the information whether an entity did or didn't exist, and that's important (to know if a translation exists and happens to be "" or if it doesn't exist at all). In the code above, I can't distinguish between the case for i3
and i4
.
Associative arrays
This also works for associative arrays:
unset j declare -gA j j[one]="Eén" j[two]="" [[ -v j[one] ]] && echo "true - j[one]" # True: Entity is set and has a value [[ -v j[two] ]] && echo "true - j[two]" # True: Entity is set (may be empty) [[ -v j[three] ]] && echo "true - j[three]" # False: The entity is unset
Associative arrays with variable indices
This works:
# Can I detect that j[1,en] is missing? # unset j declare -gA j i=1 j[$i,nl]="Eén" j[$i,de]="" [[ -v j[$i,nl] ]] && echo "true - case 1" # True: Variable is set (may be empty) [[ -v j[$i,de] ]] && echo "true - case 2" # True: Variable is set (may be empty) [[ -v j[$i,en] ]] && echo "true - case 3" # False: Variable is not set
Just... whatever
if [ -n "$var" ]; then # # var has a non-zero length ("-n": "non-zero") # fi if [ "$var" ]; then # # var has non-zero length # fi if [ -z "$var" ]; then # # var has zero length # fi if [ ! "$var" ]; then # # var has zero length # fi
But what is the best way to test for null
or for an empty string? Well, that depends. This overview may look impressive, it isn't complete: -v
is not included (which uses variable names without $
and that's probably exactly what I need to detect a set from an unset variable:
1a 2a 3a 4a 5a 6a |1b 2b 3b 4b 5b 6b [ [" [-n [-n" [-z [-z" |[[ [[" [[-n [[-n" [[-z [[-z" unset: false false true false true true |false false false false true true null : false false true false true true |false false false false true true space: false true true true true false |true true true true false false zero : true true true true false false |true true true true false false digit: true true true true false false |true true true true false false char : true true true true false false |true true true true false false hyphn: true true true true false false |true true true true false false two : -err- true -err- true -err- false |true true true true false false part : -err- true -err- true -err- false |true true true true false false Tstr : true true -err- true -err- false |true true true true false false Fsym : false true -err- true -err- false |true true true true false false T= : true true -err- true -err- false |true true true true false false F= : false true -err- true -err- false |true true true true false false T!= : true true -err- true -err- false |true true true true false false F!= : false true -err- true -err- false |true true true true false false Teq : true true -err- true -err- false |true true true true false false Feq : false true -err- true -err- false |true true true true false false Tne : true true -err- true -err- false |true true true true false false Fne : false true -err- true -err- false |true true true true false false
Voorbeeld (feb. 2016):
#!/bin/bash sleutel=$1 if [ -z $sleutel ]; then echo "Er mankeert iets aan de eerste inputvariabele"; fi
Resultaat:
Invoer Evaluatie ------ --------- * Geen invoer True * "" True * " " True * Spaties True * Hoihallo False
Variable value comparison
a=12; [ $a = 12 ] && echo "12!" # OK a=10; [ $a = 12 ] && echo "12!" # OK a=12; [ $a=12 ] && echo "12!" # Doesn't work a=12; [$a=12] && echo "12!" # Doesn't work a=12; [$a = 12] && echo "12!" # Error: bash: [12: command not found a=12; [[ $a = 12 ]] && echo "12!" # OK
String value comparison
echo "" echo "### Disable Apache virtual host..." # read -p "Continue (y/n)? " continue if [ "$continue" = "y" ] then echo "Input was 'y'" else echo "Input was not 'y'" fi
Compare for one letter using regex
Note to self: This is with a regular expression that checks for the existence of just one letter
if [[ "$switches" =~ [f] ]]; then echo "f - Create folder structure" mappenstructuur=true fi if [[ "$switches" =~ [v] ]]; then echo "v - Create virtual host file" virtueelhostbestand=true fi if [[ "$switches" =~ [h] ]]; then echo "h - Create /etc/hosts entry" voegtoehostbestand=true fi if [[ "$switches" =~ [a] ]]; then echo "a - Activate Apache" activeersite=true fi if [[ "$switches" =~ [r] ]]; then echo "r - Configure rights on folders & files" configureerrechten=true fi if [[ "$switches" =~ [b] ]]; then echo "b - Create bash alias" maakalias=true fi
Compare for substring (2)
You have to use double '['. Otherwise an error [: too many arguments will follow:
echo " Path: $path" if [[ "$path"=="/var/www/"* ]] then echo " Directory exists & contains '/var/www/" # delete_files else echo " Directory 'path' not found or doesn't contain '/var/www/' - Skip deleting files" fi
Multiple clauses
In this case, the second clause needs a double '[' & ']'. The first clause doesn't.
# Delete files ######################################## # # Let's be extra secure here: Check that the directory exists and that it # starts with "/var/www/ # if [ -d "$path" ] && [[ "$path" == "/var/www/"* ]] then delete_files else echo " Variable 'path' not found or doesn't start with '/var/www/' - Skip deleting files" fi
Check for existence of a file
Source: wp_update_site.sh
:
# valid "working_dir"? ######################################## # if [ ! -f "$working_dir/wp-config.php" ] then echo " File $working_dir/wp-config.php not found. Exiting" exit else echo " Path seems correct" fi
Check for existence of a directory
Same example as before:
# Delete files ######################################## # # Let's be extra secure here: Check that the directory exists and that it # starts with "/var/www/ # if [ -d "$path" ] && [[ "$path" == "/var/www/"* ]] then delete_files else echo " Variable 'path' not found or doesn't start with '/var/www/' - Skip deleting files" fi
String comparison with regular expressions
Back to an earlier example: The operator =~
indicates that comparison is done using regular expressions.
The wonderful world of regular expressions, and in this case, of Bash regular expressions, deserves its own page: Regular expressions (Bash).
Multiple conditions
This works, but I don't yet understand this syntax:
if [[ "$site_cat" =~ "_bal_" ]] && [[ "$site_cat" =~ "_cb_" ]]
- Double "[]" needed around both cases
- This comparison uses regular expressions, and in this specific case, the argument needs to be within ""
Logical or (not tested):
<pre> if [[ "$site_cat" =~ "_bal_" ]] || [[ "$site_cat" =~ "_cb_" ]]
not + regex (=~)
file: O&O » Bash » compare.sh:
################################################################################ # "=~" (regex) + not ################################################################################ # # I haven't found a way yet with the negation inside the brackts - That would # seem more intuitive to me. Anyhow - It works # a="blub" # echo "1 (a=blub)..." # if [[ $a =~ "blub" ]] then echo "a =~ blub" else echo "a not =~ blub" fi echo "2 (a=blub)..." # if ! [[ $a =~ "blub" ]] then echo "a not =~ blub" else echo "a =~ blub" fi a="doei" # echo "3 (a=doei)..." # if [[ $a =~ "doei" ]] then echo "a =~ doei" else echo "a not =~ doei" fi echo "4 (a=doei)..." # if ! [[ $a =~ "doei" ]] then echo "a not =~ doei" else echo "a =~ doei" fi