1

Actually, I am doing some assignment by follow:

1: Write a program called valid that prints "yes" if its argument is a valid shell variable name and "no" otherwise:

What I am doing is I want to find some value which includes some regular expression, such as [0-9]* by using 'grep' command. But I have no idea how to grab some value including that expression from the argument I input, since 'grep' command is basically to capture some line in the file. Any help will be really appreciated

4
  • 1
    Do you think they’re expecting a bash script from you? And that the valid variable name is for the bash shell? How much have you learned this far, besides grep? Anything about referring to script parap?
    – Jeff Schaller
    May 30, 2018 at 20:17
  • Yes, I need to code for a bash script. When script name is 'valid', and I run it as follow: valid 1234 -> it has to print yes or no depending on argument is correct name of variable May 30, 2018 at 20:23
  • It seems like the piece you're missing is how to get the argument. In bash, they are known as the "positional parameters", $1, $2, etc May 30, 2018 at 20:32
  • 4 answers and still no grep!
    – Jeff Schaller
    May 30, 2018 at 21:57

4 Answers 4

3

This doesn't use grep, but as a point of reference, you could use bash's =~ conditional operator to compare the script's first argument with the regular expression class for a name, which is defined by the Bash Reference Manual as:

A word consisting solely of letters, numbers, and underscores, and beginning with a letter or underscore. Names are used as shell variable and function names.

$ cat isvarname
#!/bin/bash
if [ "$#" -ne 1 ]
then
   echo "Usage: $0 a-string"
   exit 1
fi

if [[ "$1" =~ ^[[:alpha:]_][[:alnum:]_]*$ ]]
then
  echo yes
else
  echo no
fi
3
  • Thank you very much and it was very helpful. By the way, how would you know that regular expression? such as =~ ^[[:alpha:]_][[:alnum:]_]*$ ]] May 30, 2018 at 20:33
  • Please don't rush to accept this answer, particularly since I avoided using grep! =~ accepts regular expressions, so I just did it in-shell. To learn more, start with conditional expressions and man -s7 regex for a list of character classes. See the regular-expression tag on this site for more, such as unix.stackexchange.com/questions/119905/…
    – Jeff Schaller
    May 30, 2018 at 20:37
  • 1
    Can use extended pattern instead of regex: [[ $1 == [[:alpha:]_]*([[:alnum:]_]) ]] May 30, 2018 at 20:40
1

In bash a valid variable name is made of one or more single-byte characters with the first one being alphabetical or underscore, and the remaining ones if any being alphabetical, 0123456789 or underscore.

For instance Stéphane is a valid variable name only in locales where é is single-byte like in ISO-8859-1 where it's the 0xE9 byte, not in UTF-8 where it's encoded as 0xC3 0xA9.

You could do something like:

#! /usr/bin/env bash
is_single_byte() {
  local length_in_bytes length_in_chars
  length_in_chars=${#1}
  local LC_ALL=C
  length_in_bytes=${#1}
  ((length_in_bytes == length_in_chars))
}

re='^[[:alpha:]_][[:alnum:]_]*$'
for var do
  if is_single_byte "$var" && [[ $var =~ $re ]]; then
    printf '"%s" is a valid variable name\n' "$var"
  else
    printf '"%s" is not a valid variable name\n' "$var"
  fi
done
0

The first command line argument is available as $1. A valid shell variable name starts with a alphabetic character (or underscore) and continues with alphanumerics (or underscores).

Two shell patterns that matches an invalid shell variable name is

[!a-zA-Z_]*

and

[a-zA-Z_]*[!a-zA-Z_0-9]*

You may use case ... esac to do pattern matching against a variable's value.

Spoiler warning:

#!/bin/sh
LC_ALL=C
case "$1" in
    [!a-zA-Z_]*|[a-zA-Z_]*[!a-zA-Z_0-9]*|"")
        echo 'NO'
        ;;
    *)
        echo 'YES'
esac
This also answers "NO" for a variable whose name is empty. Note that this is using shell globbing patterns, not regular expressions, and that it runs in any POSIX shell, not just bash.

Testing:

$ ./script.sh _ae
YES
$ ./script.sh 0a9oe
NO
$ ./script.sh aoeat
YES
$ ./script.sh aoeat-aoe
NO
2
  • _ is a valid variable name. In most locales, [a-z] matches a lot more than the 26 English letters from a to z. Same for [0-9] and 0123456789 in some shells like bash or ksh93. May 30, 2018 at 20:45
  • @StéphaneChazelas Thanks for the reminders!
    – Kusalananda
    May 30, 2018 at 20:48
0
#!/bin/bash
var=$1
if [[ $var =~ [\`\$\=\/] || $var =~ \[ ]]; then
    echo 'no'
    exit
fi
declare "$var"=test 2>/dev/null
if [[ ${!var} == 'test' || $1 == 'var' ]]; then
    echo 'yes'
else
    echo 'no'
fi

This will try to assign the value test to the provided value. If it succeeds (if the value is a valid variable name) it will match the if test and echo yes, else it will echo no.

6
  • 3
    Generally a bad idea to use eval: bash ./your_script '(echo rm /very/important/files); foo' -- by the time the syntax error occurs, your files are already deleted. May 30, 2018 at 20:31
  • ./script '/usr/sbin/shutdown -h; x' :)
    – Jeff Schaller
    May 30, 2018 at 20:33
  • @StéphaneChazelas: Updated again, however I cannot get it to accept a[1] either way.
    – jesse_b
    May 30, 2018 at 22:25
  • @StéphaneChazelas: Quoted $var to prevent globbing. Also I would argue that it's a good thing to tell students RANDOM, EUID, and UID are not valid variable names. :p
    – jesse_b
    May 30, 2018 at 22:40
  • Modified again.
    – jesse_b
    May 30, 2018 at 22:47

You must log in to answer this question.

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