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

  • 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 '18 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 – GideokSeong May 30 '18 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 – glenn jackman May 30 '18 at 20:32
  • 4 answers and still no grep! – Jeff Schaller May 30 '18 at 21:57
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
  • Thank you very much and it was very helpful. By the way, how would you know that regular expression? such as =~ ^[[:alpha:]_][[:alnum:]_]*$ ]] – GideokSeong May 30 '18 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 '18 at 20:37
  • 1
    Can use extended pattern instead of regex: [[ $1 == [[:alpha:]_]*([[:alnum:]_]) ]] – glenn jackman May 30 '18 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
  • _ 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. – Stéphane Chazelas May 30 '18 at 20:45
  • @StéphaneChazelas Thanks for the reminders! – Kusalananda May 30 '18 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.

  • 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. – glenn jackman May 30 '18 at 20:31
  • ./script '/usr/sbin/shutdown -h; x' :) – Jeff Schaller May 30 '18 at 20:33
  • @StéphaneChazelas: Updated again, however I cannot get it to accept a[1] either way. – Jesse_b May 30 '18 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 '18 at 22:40
  • Modified again. – Jesse_b May 30 '18 at 22:47

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.