20

i would be thankfull if you could help me how to figure out, how to determine if a variable's content starts with the hash sign:

#!bin/sh    

myvar="#comment asfasfasdf"

if [ myvar = #* ] 

this does not work.

Thanks!

Jans

3
  • 1
    I would consider the possibility that there may be spaces before the hash tag as well when testing for "comments", if that is indeed what you're doing.
    – rthomson
    Apr 14, 2011 at 14:31
  • As you accepted a answer which involves a bash solution, maybe you could edit your question, as it implies you're wishing for a sh/dash solution. Oct 1, 2017 at 2:37
  • I recommend using an absolute path in the #! line as a relative path in that line is apparently taken relative to the current directory of the process executing the script rather than relative to where the script is located.
    – kasperd
    Dec 1, 2018 at 19:37

4 Answers 4

21

Your original approach would work just fine if you escaped the hash:

$ [[ '#snort' == \#* ]]; echo $?
0

Another approach would be slicing off the first character of the variable's content, using "Substring Expansion":

if [[ ${x:0:1} == '#' ]]
then
    echo 'yep'
else
    echo 'nope'
fi

yep

From the Bash man page:

   ${parameter:offset}
   ${parameter:offset:length}
          Substring  Expansion.   Expands  to  up  to length characters of
          parameter starting at the character  specified  by  offset.   If
          length  is omitted, expands to the substring of parameter start-
          ing at the character specified by offset.  length and offset are
          arithmetic   expressions   (see  ARITHMETIC  EVALUATION  below).
          length must evaluate to a number greater than or equal to  zero.
          If  offset  evaluates  to  a number less than zero, the value is
          used as an offset from the end of the value  of  parameter.   If
          parameter  is  @,  the  result  is  length positional parameters
          beginning at offset.  If parameter is an array name indexed by @
          or  *,  the  result is the length members of the array beginning
          with ${parameter[offset]}.  A negative offset is taken  relative
          to  one  greater  than the maximum index of the specified array.
          Note that a negative offset must be separated from the colon  by
          at  least  one  space to avoid being confused with the :- expan-
          sion.  Substring indexing is zero-based  unless  the  positional
          parameters are used, in which case the indexing starts at 1.
3
  • To see this man page, I should type man what?
    – duleshi
    Mar 31, 2014 at 4:17
  • It's the Bash man page, so "man bash" should do it.
    – Insyte
    Mar 31, 2014 at 21:23
  • 4
    That's bashism, but tag is about "shell" not "bash" :(.
    – pevik
    May 2, 2018 at 13:05
18

POSIX-compatible version:

[ "${var%${var#?}}"x = '#x' ] && echo yes

or:

[ "${var#\#}"x != "${var}x" ] && echo yes

or:

case "$var" in
    \#*) echo yes ;;
    *) echo no ;;
esac
4
  • 2
    +1 for the posix answer. In some rudimentary timing tests, the case method seems to be the fastest of the three on a fairly old 32-bit x86 computer. All three are far more efficient than a simple example which pipes to a forked stdin processor like: echo $var | cut -c1. My analysis was quite basic based on 10,000,000 iterations on just one computer/os - YMMV. I just used that slower computer to exaggerate any differences and make them more visible - at least on that one platform.
    – Juan
    Mar 25, 2018 at 22:22
  • BTW, for those 10,000,000 iterations, the builtin methods described in this answer ran in about a minute (on aforementioned slow box). The pipe to cut flavor took 5+ hours.
    – Juan
    Mar 26, 2018 at 21:36
  • What if you want to find things starting with "
    – Justin
    Nov 6, 2019 at 21:38
  • @Juan - It is surprising than case runs faster than parameter expansions. Any clues?
    – midnite
    Apr 17, 2023 at 9:57
6

I know this may be heresy, but for this kind of things I'd rather use grep or egrep rather than doing it from within the shell. It's a little more costly (I guess) but for me this solution's readability offsets that. It's a matter of personal taste though, of course.

So:

myvar="   #comment asfasfasdf"
if ! echo $myvar | egrep -q '^ *#'
then
  echo "not a comment"
else
  echo "commented out"
fi

It works with or without leading spaces. If you'd like to account for leading tabs also, use egrep -q '^[ \t]*#' instead.

1
  • Thinking about it perhaps I just prefer egrep because I like regexes, but I consider grep/egrep to be useful in a wider arrange of situations anyway. Apr 14, 2011 at 14:46
0

Here is another way...

# assign to var the value of argument actual invocation
var=${1-"#default string"}

if [[ "$var" == "#"* ]]
then
  echo "$var starts with a #"
fi

Just copy paste the content to a file, grant execution permissions, and watch how it just works ;).

Hope it helps!

Greetings.

1
  • 3
    That's bashism, but tag is about "shell" not "bash" :(.
    – pevik
    May 2, 2018 at 13:05

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .