FilOle
FilOle

Reputation: 53

Bash skipping iteration in for

I have to write an macro that gets few arguments to it. for example ./macro.sh -wrongone -f filename -wrongone. I have to catch the wrong ones and list them and make required operation on the valid ones. Here is my code:

for i in "${ArrayOfParameters[@]}"
do
    tmp=$[tmp+1]
    case "${i}" in

    "-h" | "--help")
        help
        ;;

    "-f")   
        a="${ArrayOfParameters[i+1]}"
        echo $a
        i=$[i+1]            
        ;;          

    *)
        echo -e "${red}Parameter ${i} is wrong!${NC}"
        ;;
    esac

done    

My problem is that I do not know how to make 'filename' to be skipped by default operation of the switch :(. Every time I get error that filename is wrong parameter. I was thinking about skipping one iteration. Something like that in C++.

for(int i=0;i<5;i++)
if(i==3)
i=4;

I would like to get something like that in Bash but no idea how to do it. Tried

for (( i=0; i<=5; i++ ))
a="${ArrayOfParameters[i]}"

but it was returning me all the time numbers not the strings. I would be really gratefull for helpfull answers.

Upvotes: 2

Views: 6785

Answers (4)

Robin Wilson
Robin Wilson

Reputation: 1

I'd recommend a 'while' loop instead. Use 'shift' to move the argument pointer to the next argument, then use "$1" to read the argument you want. You have complete control over the arguments that way:

while [ $# -gt 0 ]; do
  case "$1" in
    -f) shift
        FILE="$1"
    ;;
    -h|*) help
    ;;
  esac
  shift
done

Upvotes: 0

Savir
Savir

Reputation: 18418

If I understood correctly, you want to skip the next item after you find -f, right? If that's the case, you can use a more C-looking syntax and play with the array index, rather than with the array contents

#!/bin/bash

declare -a ArrayOfParameters=("-hello" "-howdy" "-foo bar" "-f" "-something else")

for ((i=0; i <= ${#ArrayOfParameters[@]}; i++))
do
    item=${ArrayOfParameters[i]}
    echo "Studying item number ${i} (value: ${item})"
    case "${item}" in
        "-f")   
           echo "Found -f. Skipping next."  
           ((i++))
           ;;          
        *)
           echo "NOT skipping ${item}"
           ;;
    esac
done

You'll see that it skips the item after -f:

Studying item number 0 (value: -hello)
NOT skipping -hello
Studying item number 1 (value: -howdy)
NOT skipping -howdy
Studying item number 2 (value: -foo bar)
NOT skipping -foo bar
Studying item number 3 (value: -f)
Found -f. Skipping next.
Studying item number 5 (value: )
NOT skipping 

Upvotes: 3

Siguza
Siguza

Reputation: 23840

I think the easiest solution is to use a flag variable that you set to true if '-f' matches and at the beginning of your for loop, check if that flag is set, set it to false and use continue.

skipNext=false
for i in "${ArrayOfParameters[@]}"
do
    if $skipNext
    then
        skipNext=false
        continue
    fi
    tmp=$[tmp+1]
    case "${i}" in
        "-h" | "--help")
            help
            ;;
        "-f")
            skipNext=true
            a="${ArrayOfParameters[i+1]}"
            echo $a
            i=$[i+1]            
            ;;
        *)
            echo -e "${red}Parameter ${i} is wrong!${NC}"
            ;;
    esac
done  

Upvotes: 0

tgo
tgo

Reputation: 1545

Not a direct answer to your coding problem, but I think you should do yourself a favor and use getopts (see here for a good tutorial). Handling parameters is usually messy and there are a lot of corner cases, so rolling your own is not always a good idea.

Upvotes: 4

Related Questions