Find the answer to your Linux question:
Results 1 to 5 of 5
Hi, all. I have a script that can take multiple arguments. The arguments are either integers or characters such as "jsousa". Here's the usage where [] means optional: Code: script_name ...
  1. #1
    Just Joined!
    Join Date
    Oct 2008
    Posts
    11

    functions and for loops

    Hi, all.

    I have a script that can take multiple arguments. The arguments are either integers or characters such as "jsousa". Here's the usage where [] means optional:

    Code:
    script_name 12345 [98765] [jsousa]  [bross]
    Actually, the first argument can be either an integer or a string. In my script, I have a function called, is_num() that checks if an argument is an integer. The function works so I'm not worried about that. But the code I wrote that uses the function doesn't. First, here's a simplified version of my code that DOES work. It says:


    If the argument is a number, then print PASS
    If the argument is not a number, then print FAIL


    Code:
      for arg; do
    
        if is_num $arg; then
          print "PASS: " $arg
        else
          print "FAIL: " $arg
        fi
    
      done

    This input:
    Code:
    script_name 12345 jsousa
    Produces this output:
    Code:
    PASS:  12345
    FAIL:  jsousa

    All is well. But when i expand my PASS section and insert a for loop, I get very different results. I was expecting that only the arguments that pass the is_num function would run through my inner for loop. But ALL of my arguments are running through it. I don't understand why.

    Code:
      for arg; do
    
        if is_num $arg; then
    
          for arg; do
            print "PASS: " $arg
          done
    
        else
          print "FAIL: " $arg
        fi
    
      done

    Now this input:
    Code:
    script_name 12345 jsousa
    Produces this output:
    Code:
    PASS:  12345
    PASS:  jsousa
    FAIL:  jsousa


    Why is "jsousa" passing? Why is it getting past is_num()?


    Thanks for your help and let me know if I am not being clear.

  2. #2
    Trusted Penguin Cabhan's Avatar
    Join Date
    Jan 2005
    Location
    Seattle, WA, USA
    Posts
    3,230
    So this is related to the syntax of a Bash for loop. The formal syntax is:
    Code:
    for <var> [in <list>]; do <body>; done
    If the list is omitted, then by default it will loop through the arguments to the script.

    So let's see what happens:

    So we start with the outer loop, looping through each argument to the script. The first argument is 98765. Is it a number? Yes. In that case, we loop through each argument to the script, printing "PASS: $arg" for each one. So we print "PASS: 98765", then "PASS: jsousa".

    Now we go back to the outer loop. Now we're on the second argument: "jsousa". Is it a number? No. So we print "FAIL: jsousa".

    Does this make sense?

    My immediate question is why do you have this inner for loop? What is it supposed to do? Shouldn't you only be passing the one variable that passed? I don't understand the loop.

    Hope that helps.
    DISTRO=Arch
    Registered Linux User #388732

  3. #3
    Just Joined!
    Join Date
    Jul 2008
    Posts
    73
    I agree with the previous poster, except I am of the opinion that you should move the if statement inside the loop, looping through the arguments then would produce the results you are looking for.

    Later, Ray Parrish

    Never mind, just saw the outer loop, yes I agree the inner loop is redundant and is causing the problem.

  4. #4
    Just Joined!
    Join Date
    Oct 2008
    Posts
    11
    Hi, again.

    Thanks so much for all of your repsonses. They really help. The reason I use an inner for loop is that 1) I thought that the outer one would filter out all non-numbers, and 2) I need to verify that the numbers themselves match nummbers in a file called, master_file. Here's my real code:


    Code:
    is_num()
    {
      (( $# == 0 ))&&print "Usage: is_num number" && exit 1
      a=$(echo "$1" | grep "^[0-9]\{5\}$")
      [ -n "$a" ] && return 0 || return 1
    }
    
      for arg; do
        if is_num $arg; then
    
          for num; do
            a=$(grep "^x$num:" master_file)
            [ -z "$a" ] && print "WARNING:" $num "is not in mastet_file" && continue
            f2=$(echo $a | cut -d: -f2)
    
            if [ -z "$f2" ]; then
                print "WARNING:" $num "does not have any users in master_file."
            else
              print $f2 | tr ',' '\n' >> list_users
              continue
            fi
          done
    
        else
            echo $arg >> list_users
        fi
      done


    Is there a way around this dilemna? Can I do something else to ensure that only numbers enter the inner loop?


    Thanks.

  5. #5
    Trusted Penguin Cabhan's Avatar
    Join Date
    Jan 2005
    Location
    Seattle, WA, USA
    Posts
    3,230
    Interesting, and good to know the context, but I still don't understand why you would need the inner loop.

    Each iteration of the outer loop is for one argument. If you just put the conditional directly into this loop, it will be applied to one argument at a time, and action taken if it's a number. The inner loop isn't looping over anything, so there's no need to have a loop.
    DISTRO=Arch
    Registered Linux User #388732

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
...