16

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

  • 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 '11 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. – Charles Roberto Canato Oct 1 '17 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 '18 at 19:37
20

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.
  • To see this man page, I should type man what? – duleshi Mar 31 '14 at 4:17
  • It's the Bash man page, so "man bash" should do it. – Insyte Mar 31 '14 at 21:23
  • 2
    That's bashism, but tag is about "shell" not "bash" :(. – pevik May 2 '18 at 13:05
11

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
  • 1
    +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 '18 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 '18 at 21:36
5

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.

  • 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. – Eduardo Ivanec Apr 14 '11 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
    That's bashism, but tag is about "shell" not "bash" :(. – pevik May 2 '18 at 13:05

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.