In Bash, how can I check if a string begins with some value?
This snippet on the Advanced Bash Scripting Guide says:
# The == comparison operator behaves differently within a double-brackets# test than within single brackets.[[ $a == z* ]] # True if $a starts with a "z" (wildcard matching).[[ $a == "z*" ]] # True if $a is equal to z* (literal matching).
So you had it nearly correct; you needed double brackets, not single brackets.
With regards to your second question, you can write it this way:
HOST=user1if [[ $HOST == user1 ]] || [[ $HOST == node* ]] ;then echo yes1fiHOST=node001if [[ $HOST == user1 ]] || [[ $HOST == node* ]] ;then echo yes2fi
Which will echo
yes1yes2
Bash's if
syntax is hard to get used to (IMO).
If you're using a recent version of Bash (v3+), I suggest the Bash regex comparison operator =~
, for example,
if [[ "$HOST" =~ ^user.* ]]; then echo "yes"fi
To match this or that
in a regex, use |
, for example,
if [[ "$HOST" =~ ^user.*|^host1 ]]; then echo "yes"fi
Note - this is 'proper' regular expression syntax.
user*
meansuse
and zero-or-more occurrences ofr
, souse
anduserrrr
will match.user.*
meansuser
and zero-or-more occurrences of any character, souser1
,userX
will match.^user.*
means match the patternuser.*
at the begin of $HOST.
If you're not familiar with regular expression syntax, try referring to this resource.
Note that the Bash =~
operator only does regular expression matching when the right hand side is UNQUOTED. If you do quote the right hand side, "any part of the pattern may be quoted to force it to be matched as a string.". You should not quote the right hand side even when doing parameter expansion.
I always try to stick with POSIX sh
instead of using Bash extensions, since one of the major points of scripting is portability (besides connecting programs, not replacing them).
In sh
, there is an easy way to check for an "is-prefix" condition.
case $HOST in node*) # Your code hereesac
Given how old, arcane and crufty sh is (and Bash is not the cure: It's more complicated, less consistent and less portable), I'd like to point out a very nice functional aspect: While some syntax elements like case
are built-in, the resulting constructs are no different than any other job. They can be composed in the same way:
if case $HOST in node*) true;; *) false;; esac; then # Your code herefi
Or even shorter
if case $HOST in node*) ;; *) false;; esac; then # Your code herefi
Or even shorter (just to present !
as a language element -- but this is bad style now)
if ! case $HOST in node*) false;; esac; then # Your code herefi
If you like being explicit, build your own language element:
beginswith() { case $2 in "$1"*) true;; *) false;; esac; }
Isn't this actually quite nice?
if beginswith node "$HOST"; then # Your code herefi
And since sh
is basically only jobs and string-lists (and internally processes, out of which jobs are composed), we can now even do some light functional programming:
beginswith() { case $2 in "$1"*) true;; *) false;; esac; }checkresult() { if [ $? = 0 ]; then echo TRUE; else echo FALSE; fi; }all() { test=$1; shift for i in "$@"; do $test "$i" || return done}all "beginswith x" x xy xyz ; checkresult # Prints TRUEall "beginswith x" x xy abc ; checkresult # Prints FALSE
This is elegant. Not that I'd advocate using sh
for anything serious -- it breaks all too quickly on real world requirements (no lambdas, so we must use strings. But nesting function calls with strings is not possible, pipes are not possible, etc.)