argument count

I'm writing a program that takes input from the user of a phone number or a name then either tells them if that entry doesn't exist in a text document or returns the entry if it does exist. But if they enter a name AND number it either returns the entry if it exists or adds it to the document.
To do this involves lots of if statements etcetc but to start I need to know how to tell the program if the user has only put in a number or name or if they've put in both name and number.

Long rant short is there a statement that tests if 1 or two arguments have been inputted?
would the following work?

if [ $1$2 ]
#test for number and name in document
elif [ $1 ] 
#test if its a valid number or name then test if it's in document

I would think the presence of a second input variable would be enough:

if [ -n $2 ]
#do this
else
#do this

of course you could always use a case statement, i guess it would depend on the number of variables you are testing for

Thanks for your help.
Well the first variable is 1 argument or 2, then (if 1) number or name then validating the number or name then checking if the number/name is in the document (if 2) validating the number and name, checking if it's in the document and adding.
I was thinking having an outer if statment then cases in them to validate with if statements in those to check the document. Ah nesting, gotta love it.
With your [ -n $2 ] I'll be able to start it correctly.:b:
Thanks very much :slight_smile:

Maybe you want something like this:

#!/bin/sh
NAME= NUMBER=
while $# -gt 0; do
    if echo $1 | grep -qv '[^0-9-]'; then
        # $1 contains only digits and dashes
        test -n "$NUMBER"  &&  { echo "Too many numbers"; exit 1; }
        NUMBER=$1
    else
        test -n "$NAME"  &&  { echo "Too many names"; exit 1; }
        NAME="$1"
    fi
    shift
done

# Now process $NAME and $NUMBER if they aren't blank

I think grep -qv '[^0-9-]' is clever.
It quietly returns true if the value piped in does not contain any characters that are not digits or hyphens.
That is, if true, it only contains those characters.

-------------
Oops. I for forgot the brackets. The 'while' line should be:
while [ $# -gt 0 ]; do
or
while test $# -gt 0; do

lol well my next question was how do I determine input is digits or not?
I tried the if echo $1 | grep -qv '[^0-9-]'
but it doesn't appear to accept it as false if I enter a name ie enter 12345678 and it does the number part enter bob and it says invalid number.

Also after I get that figured out how do I get the line from the document that contains the name or number ie entered "bob jones" and it was found in the document. It needs to echo that result
ie Bob Jones 12345567
is there a grep option that returns the line itself?

Have you thought of maybe adding an option to your script:

script.sh --number 123456789
script.sh --name "Jim Jones"

That way you would be able to determine what type of validation you should apply. Also you may want to try this regular expression to match the number:

[0-9-]+

It will match more than one instance, I think yours was stopping at the first instance the expression was satisfied.

Try this from the command line:

echo 1234 | grep -qv '[^0-9-]'  &&  echo RIGHT
echo 12A34 | grep -qv '[^0-9-]'  &&  echo WRONG

What's the format of your file? Maybe something as simple as this:

grep "$NAME" file.txt

Yay! thanks for that. I got the check numbers grep thing working fine but it still seems to have a problem with how many arguments were entered. If i use [ -n $2 ] it just runs like there is one no matter what,
[ $# -gt 0 ] always thinks there is 2. :frowning:

---------- Post updated at 10:51 PM ---------- Previous update was at 10:41 PM ----------

Here's my code just in case it's something obvious i've done that's stopping it from working:

if [ -f $directory ]   
then
#This will take the number and/or name from the user storing it into $input
        echo -e "Input name or/and number: \c";
        read input
        #This if statement checks to see if the user inputted 1 argument ie name OR number or 2 ie name AND number
        if [ $# -ne 2 ]              
        then
        #This line checks to see if the input contains only digits or hyphens
                if echo $input | grep -qv '[^0-9-]' 
                        then
                        #This case will take the input and check it is a valid number (8digits not starting with 0)
                        case $input in
                        [1-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9])
                        continue;;
                        *) echo "invalid number"; exit
                        esac
else
                        #This case will test if an inputed name is valid.
                        case $input in
                        [!\ a-zA-Z]*) echo "invalid name" ; exit
                        continue ;;
                        *[a-zA-Z]*)
                        continue ;;
                        esac
                fi
        #If the name or number was valid this block of commands will run, checking the #directory for the name/number and returning either no such entry or the entry itself.
        grep "$input" teledir.txt>/dev/null     
        work=$?
        if [ $work -ne 1 ]
        then
        grep "$input" teledir.txt
     else
        echo "No such entry"
        fi
          
        #If 2 statements were inputted this block of commands is run (ie similar but if      #entry doesn't exist it adds it instead of returning no such entry
        else
        echo "2 arguments entered"
        fi 
           
#Tells the user the Teledir.txt was not found
else
echo "Teledir.txt does not exist in this directory"
fi

You must put a shift somewhere in the loop.
It drops $1 and shifts $2 $3 ... to $1 $2 ... and decrements $#.

Is it perhaps because its an inputted value inside the program so it doesn't count as a command line? That might be why it's not counting arguments. Is there a way to remove the need for the user input line so they'd type $sh phone.sh "bob" 1234567 instead of doing it in the program itself?

I think it is wasteful. There is no need to use an external command to determine whether a string contains another string or character. Use case. For example:

case $1 in
   [!0-9-]* | *[!0-9]* ) echo contains non-numbers ;;
   *) echo numbers only ;;
esac

Hey cfajohnson,

The breadth of your scripting knowledge continues to amaze me. I can't remember ever seeing the sequence [! in any script.

But I found it in the Pattern Matching section of Filename Expansion in the Bash Manual. (Though you could have used the more familiar [^.)

Never-the-less, there are still two arguments in favour of my solution:

  1. Once Linux has executed the grep executable, it remains in memory, so it takes negligible time to execute, and
  2. My solution can fit within the test of a larger and more complex if-then-else sequence.

It's a basic pattern. I use it a lot.

That is not POSIX and not portable.

The time to fork and exec an external command it still many times longer than a purely shell solution.

As can mine.

Are you saying that the syntax of [!...] as described in the Filename Expansion section of the Bash manual is not POSIX and not portable?
Or do you just mean that Bash in general is not POSIX and not portable?

Oh! I just found a document from the OpenGroup that describes Pattern Matching Notation which says, A bracket expression starting with an unquoted <circumflex> character produces unspecified results. Great! A built-in gotcha.

It is true that Bash has extensions beyond POSIX, and therefore if something works perfectly in the Bash shell, there is no guarantee it will work in some other shell. For that reason there is wisdom in insisting on POSIX compatibility as you do.

But one has to consider the context in which one codes. Many scripts will never be used outside of Bash, or even be seen by someone who holds Bash extensions in other than the highest regard. If one writes a Perl or Python script, it's not wrong to require that it only be run on systems with Perl or Python installed. I don't think it's out of order to view Bash scripts similarly.

If you use non-standard syntax, you should expect to have problems.

Absolutely.

There is a major difference between a shell and perl or python. A shell is a necessary component of a system; perl and python are not.

When I write a script, I try to write it using a portable (i.e. POSIX) syntax. If writing for bash, I may use bash extensions, but I never use bash-only syntax for something that can be coded with POSIX syntax.

Okay it turned out that no matter what I do $# wasn't returning anything but 0 which is why it wasn't working correctly. I'm looking into the problem now.

Ha figured it out. Apparently I was right about it not liking to count arguments in a variable, it had to be added inthe command line when the script itself was called.
Thanks for your help all. My program works great now :slight_smile: THANKYOU!

javajynx can you please post the working code so i can follow what you have been doing to make it work thank you.