while check if a variable is in an array bash

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP











up vote
0
down vote

favorite












I have a bug in my while loop check. I am checking if the user input is a valid user interface. This is my code:



#!/bin/bash

net_array=()
for iface in $(ifconfig | cut -d ' ' -f1| tr ':' 'n' | awk NF)
do
net_array+=("$iface")
done
unset "net_array[$#net_array[@]-1]"

# Network Interface selection

printf "nPlease select the network interface you want to use:n"
read -r user_iface

while ! [[ "$net_array[@]" =~ $user_iface ]]; do # check if the user input is valid
echo "Please enter a valid network interface:"
read -r user_iface
done


Generally this code works and checks if the element is in the array. My PC has eno1, eno2, eno3 interfaces and when I insert something different like eno5 it asks me again to insert the network interface.



The problem is that if I insert only 1, it accepts it as a valid network interface, which is not the case and I want to exclude it. I guess I can perform additional check excluding all numerical user inputs, but I am wondering what my error is?







share|improve this question
























    up vote
    0
    down vote

    favorite












    I have a bug in my while loop check. I am checking if the user input is a valid user interface. This is my code:



    #!/bin/bash

    net_array=()
    for iface in $(ifconfig | cut -d ' ' -f1| tr ':' 'n' | awk NF)
    do
    net_array+=("$iface")
    done
    unset "net_array[$#net_array[@]-1]"

    # Network Interface selection

    printf "nPlease select the network interface you want to use:n"
    read -r user_iface

    while ! [[ "$net_array[@]" =~ $user_iface ]]; do # check if the user input is valid
    echo "Please enter a valid network interface:"
    read -r user_iface
    done


    Generally this code works and checks if the element is in the array. My PC has eno1, eno2, eno3 interfaces and when I insert something different like eno5 it asks me again to insert the network interface.



    The problem is that if I insert only 1, it accepts it as a valid network interface, which is not the case and I want to exclude it. I guess I can perform additional check excluding all numerical user inputs, but I am wondering what my error is?







    share|improve this question






















      up vote
      0
      down vote

      favorite









      up vote
      0
      down vote

      favorite











      I have a bug in my while loop check. I am checking if the user input is a valid user interface. This is my code:



      #!/bin/bash

      net_array=()
      for iface in $(ifconfig | cut -d ' ' -f1| tr ':' 'n' | awk NF)
      do
      net_array+=("$iface")
      done
      unset "net_array[$#net_array[@]-1]"

      # Network Interface selection

      printf "nPlease select the network interface you want to use:n"
      read -r user_iface

      while ! [[ "$net_array[@]" =~ $user_iface ]]; do # check if the user input is valid
      echo "Please enter a valid network interface:"
      read -r user_iface
      done


      Generally this code works and checks if the element is in the array. My PC has eno1, eno2, eno3 interfaces and when I insert something different like eno5 it asks me again to insert the network interface.



      The problem is that if I insert only 1, it accepts it as a valid network interface, which is not the case and I want to exclude it. I guess I can perform additional check excluding all numerical user inputs, but I am wondering what my error is?







      share|improve this question












      I have a bug in my while loop check. I am checking if the user input is a valid user interface. This is my code:



      #!/bin/bash

      net_array=()
      for iface in $(ifconfig | cut -d ' ' -f1| tr ':' 'n' | awk NF)
      do
      net_array+=("$iface")
      done
      unset "net_array[$#net_array[@]-1]"

      # Network Interface selection

      printf "nPlease select the network interface you want to use:n"
      read -r user_iface

      while ! [[ "$net_array[@]" =~ $user_iface ]]; do # check if the user input is valid
      echo "Please enter a valid network interface:"
      read -r user_iface
      done


      Generally this code works and checks if the element is in the array. My PC has eno1, eno2, eno3 interfaces and when I insert something different like eno5 it asks me again to insert the network interface.



      The problem is that if I insert only 1, it accepts it as a valid network interface, which is not the case and I want to exclude it. I guess I can perform additional check excluding all numerical user inputs, but I am wondering what my error is?









      share|improve this question











      share|improve this question




      share|improve this question










      asked Dec 23 '17 at 8:38









      Georgе Stoyanov

      16515




      16515




















          1 Answer
          1






          active

          oldest

          votes

















          up vote
          6
          down vote













          The regex match [[ string =~ pattern ]] doesn't actually match against the full string, but searches for the pattern in the string (like grep). You'd need to lock the pattern to the beginning and end of line, with the ^ and $ special characters ("anchors").



          So, you could do



          [[ "$a" =~ ^"$b"$ ]]


          quoting the variable so that its contents are not taken as a regex.



          Though, since you only want to find full matches, why use a regex match at all, just compare for equality:



          [[ "$a" = "$b" ]]


          Except that of course your left hand side wasn't a single array item, but the whole array. Finding a matching in item an array with a pattern match like that is somewhat tricky, it was discussed here Using case and arrays together in bash (in relation to case, but a pattern match anyway).



          In brief, you could do something like this, searching for the chosen item with a space or start/end of string on both sides:



          [[ "$net_array[*]" =~ (^| )"$user_iface"( |$) ]]


          It should work as long as the user doesn't enter any whitespace, though we could of course change IFS to get another separator.




          But I would just loop over the array elements and check for a match:



          found=0
          for a in "$net_array[@]" ; do
          [[ "$a" = "$user_iface" ]] && found=1
          done


          Or put the loop in a function:



          contains() 
          typeset _x;
          typeset -n _A="$1"
          for _x in "$_A[@]" ; do
          [ "$_x" = "$2" ] && return 0
          done
          return 1



          and then the whole asking for input thing would something like this



          while read -p "please enter a network interface: " -r user_iface; 
          ! contains net_array "$user_iface" ; do
          echo "$user_iface is not a valid interface!"
          done



          ... or just use select and save the users some typing:



          select choice in "$net_array[@]" ; do 
          if [[ "$choice" ]]; then break; else echo "invalid choice!"; fi;
          done;
          echo "you chose $choice";


          (it loops until you break out)






          share|improve this answer






















            Your Answer







            StackExchange.ready(function()
            var channelOptions =
            tags: "".split(" "),
            id: "106"
            ;
            initTagRenderer("".split(" "), "".split(" "), channelOptions);

            StackExchange.using("externalEditor", function()
            // Have to fire editor after snippets, if snippets enabled
            if (StackExchange.settings.snippets.snippetsEnabled)
            StackExchange.using("snippets", function()
            createEditor();
            );

            else
            createEditor();

            );

            function createEditor()
            StackExchange.prepareEditor(
            heartbeatType: 'answer',
            convertImagesToLinks: false,
            noModals: false,
            showLowRepImageUploadWarning: true,
            reputationToPostImages: null,
            bindNavPrevention: true,
            postfix: "",
            onDemand: true,
            discardSelector: ".discard-answer"
            ,immediatelyShowMarkdownHelp:true
            );



            );








             

            draft saved


            draft discarded


















            StackExchange.ready(
            function ()
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f412641%2fwhile-check-if-a-variable-is-in-an-array-bash%23new-answer', 'question_page');

            );

            Post as a guest






























            1 Answer
            1






            active

            oldest

            votes








            1 Answer
            1






            active

            oldest

            votes









            active

            oldest

            votes






            active

            oldest

            votes








            up vote
            6
            down vote













            The regex match [[ string =~ pattern ]] doesn't actually match against the full string, but searches for the pattern in the string (like grep). You'd need to lock the pattern to the beginning and end of line, with the ^ and $ special characters ("anchors").



            So, you could do



            [[ "$a" =~ ^"$b"$ ]]


            quoting the variable so that its contents are not taken as a regex.



            Though, since you only want to find full matches, why use a regex match at all, just compare for equality:



            [[ "$a" = "$b" ]]


            Except that of course your left hand side wasn't a single array item, but the whole array. Finding a matching in item an array with a pattern match like that is somewhat tricky, it was discussed here Using case and arrays together in bash (in relation to case, but a pattern match anyway).



            In brief, you could do something like this, searching for the chosen item with a space or start/end of string on both sides:



            [[ "$net_array[*]" =~ (^| )"$user_iface"( |$) ]]


            It should work as long as the user doesn't enter any whitespace, though we could of course change IFS to get another separator.




            But I would just loop over the array elements and check for a match:



            found=0
            for a in "$net_array[@]" ; do
            [[ "$a" = "$user_iface" ]] && found=1
            done


            Or put the loop in a function:



            contains() 
            typeset _x;
            typeset -n _A="$1"
            for _x in "$_A[@]" ; do
            [ "$_x" = "$2" ] && return 0
            done
            return 1



            and then the whole asking for input thing would something like this



            while read -p "please enter a network interface: " -r user_iface; 
            ! contains net_array "$user_iface" ; do
            echo "$user_iface is not a valid interface!"
            done



            ... or just use select and save the users some typing:



            select choice in "$net_array[@]" ; do 
            if [[ "$choice" ]]; then break; else echo "invalid choice!"; fi;
            done;
            echo "you chose $choice";


            (it loops until you break out)






            share|improve this answer


























              up vote
              6
              down vote













              The regex match [[ string =~ pattern ]] doesn't actually match against the full string, but searches for the pattern in the string (like grep). You'd need to lock the pattern to the beginning and end of line, with the ^ and $ special characters ("anchors").



              So, you could do



              [[ "$a" =~ ^"$b"$ ]]


              quoting the variable so that its contents are not taken as a regex.



              Though, since you only want to find full matches, why use a regex match at all, just compare for equality:



              [[ "$a" = "$b" ]]


              Except that of course your left hand side wasn't a single array item, but the whole array. Finding a matching in item an array with a pattern match like that is somewhat tricky, it was discussed here Using case and arrays together in bash (in relation to case, but a pattern match anyway).



              In brief, you could do something like this, searching for the chosen item with a space or start/end of string on both sides:



              [[ "$net_array[*]" =~ (^| )"$user_iface"( |$) ]]


              It should work as long as the user doesn't enter any whitespace, though we could of course change IFS to get another separator.




              But I would just loop over the array elements and check for a match:



              found=0
              for a in "$net_array[@]" ; do
              [[ "$a" = "$user_iface" ]] && found=1
              done


              Or put the loop in a function:



              contains() 
              typeset _x;
              typeset -n _A="$1"
              for _x in "$_A[@]" ; do
              [ "$_x" = "$2" ] && return 0
              done
              return 1



              and then the whole asking for input thing would something like this



              while read -p "please enter a network interface: " -r user_iface; 
              ! contains net_array "$user_iface" ; do
              echo "$user_iface is not a valid interface!"
              done



              ... or just use select and save the users some typing:



              select choice in "$net_array[@]" ; do 
              if [[ "$choice" ]]; then break; else echo "invalid choice!"; fi;
              done;
              echo "you chose $choice";


              (it loops until you break out)






              share|improve this answer
























                up vote
                6
                down vote










                up vote
                6
                down vote









                The regex match [[ string =~ pattern ]] doesn't actually match against the full string, but searches for the pattern in the string (like grep). You'd need to lock the pattern to the beginning and end of line, with the ^ and $ special characters ("anchors").



                So, you could do



                [[ "$a" =~ ^"$b"$ ]]


                quoting the variable so that its contents are not taken as a regex.



                Though, since you only want to find full matches, why use a regex match at all, just compare for equality:



                [[ "$a" = "$b" ]]


                Except that of course your left hand side wasn't a single array item, but the whole array. Finding a matching in item an array with a pattern match like that is somewhat tricky, it was discussed here Using case and arrays together in bash (in relation to case, but a pattern match anyway).



                In brief, you could do something like this, searching for the chosen item with a space or start/end of string on both sides:



                [[ "$net_array[*]" =~ (^| )"$user_iface"( |$) ]]


                It should work as long as the user doesn't enter any whitespace, though we could of course change IFS to get another separator.




                But I would just loop over the array elements and check for a match:



                found=0
                for a in "$net_array[@]" ; do
                [[ "$a" = "$user_iface" ]] && found=1
                done


                Or put the loop in a function:



                contains() 
                typeset _x;
                typeset -n _A="$1"
                for _x in "$_A[@]" ; do
                [ "$_x" = "$2" ] && return 0
                done
                return 1



                and then the whole asking for input thing would something like this



                while read -p "please enter a network interface: " -r user_iface; 
                ! contains net_array "$user_iface" ; do
                echo "$user_iface is not a valid interface!"
                done



                ... or just use select and save the users some typing:



                select choice in "$net_array[@]" ; do 
                if [[ "$choice" ]]; then break; else echo "invalid choice!"; fi;
                done;
                echo "you chose $choice";


                (it loops until you break out)






                share|improve this answer














                The regex match [[ string =~ pattern ]] doesn't actually match against the full string, but searches for the pattern in the string (like grep). You'd need to lock the pattern to the beginning and end of line, with the ^ and $ special characters ("anchors").



                So, you could do



                [[ "$a" =~ ^"$b"$ ]]


                quoting the variable so that its contents are not taken as a regex.



                Though, since you only want to find full matches, why use a regex match at all, just compare for equality:



                [[ "$a" = "$b" ]]


                Except that of course your left hand side wasn't a single array item, but the whole array. Finding a matching in item an array with a pattern match like that is somewhat tricky, it was discussed here Using case and arrays together in bash (in relation to case, but a pattern match anyway).



                In brief, you could do something like this, searching for the chosen item with a space or start/end of string on both sides:



                [[ "$net_array[*]" =~ (^| )"$user_iface"( |$) ]]


                It should work as long as the user doesn't enter any whitespace, though we could of course change IFS to get another separator.




                But I would just loop over the array elements and check for a match:



                found=0
                for a in "$net_array[@]" ; do
                [[ "$a" = "$user_iface" ]] && found=1
                done


                Or put the loop in a function:



                contains() 
                typeset _x;
                typeset -n _A="$1"
                for _x in "$_A[@]" ; do
                [ "$_x" = "$2" ] && return 0
                done
                return 1



                and then the whole asking for input thing would something like this



                while read -p "please enter a network interface: " -r user_iface; 
                ! contains net_array "$user_iface" ; do
                echo "$user_iface is not a valid interface!"
                done



                ... or just use select and save the users some typing:



                select choice in "$net_array[@]" ; do 
                if [[ "$choice" ]]; then break; else echo "invalid choice!"; fi;
                done;
                echo "you chose $choice";


                (it loops until you break out)







                share|improve this answer














                share|improve this answer



                share|improve this answer








                edited Dec 23 '17 at 10:35

























                answered Dec 23 '17 at 9:40









                ilkkachu

                49.9k674137




                49.9k674137






















                     

                    draft saved


                    draft discarded


























                     


                    draft saved


                    draft discarded














                    StackExchange.ready(
                    function ()
                    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f412641%2fwhile-check-if-a-variable-is-in-an-array-bash%23new-answer', 'question_page');

                    );

                    Post as a guest













































































                    Popular posts from this blog

                    How to check contact read email or not when send email to Individual?

                    Displaying single band from multi-band raster using QGIS

                    How many registers does an x86_64 CPU actually have?