Why does `find` in Linux skip expected results when `-o` is used?












6














Why in Linux (Debian 8)



touch 1.cpp 1.h
find . -name "*.cpp" -o -name "*.h" -exec echo {} ;


outputs only 1.h while



find . -name "*.cpp" -o -name "*.h"


outputs both? Is it a bug or feature?










share|improve this question





























    6














    Why in Linux (Debian 8)



    touch 1.cpp 1.h
    find . -name "*.cpp" -o -name "*.h" -exec echo {} ;


    outputs only 1.h while



    find . -name "*.cpp" -o -name "*.h"


    outputs both? Is it a bug or feature?










    share|improve this question



























      6












      6








      6







      Why in Linux (Debian 8)



      touch 1.cpp 1.h
      find . -name "*.cpp" -o -name "*.h" -exec echo {} ;


      outputs only 1.h while



      find . -name "*.cpp" -o -name "*.h"


      outputs both? Is it a bug or feature?










      share|improve this question















      Why in Linux (Debian 8)



      touch 1.cpp 1.h
      find . -name "*.cpp" -o -name "*.h" -exec echo {} ;


      outputs only 1.h while



      find . -name "*.cpp" -o -name "*.h"


      outputs both? Is it a bug or feature?







      linux find






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited Feb 17 at 19:52









      Kamil Maciorowski

      24.5k155277




      24.5k155277










      asked Sep 2 '15 at 10:21









      mastan

      332




      332






















          4 Answers
          4






          active

          oldest

          votes


















          1














          I think once you used -or operator, then you've to keep it consistent in order to avoid ambiguous order of logical operations when you have multiple conditions connected using logical OR.



          It seems the -exec part is grouped together with the second -name "*.h".



          So in order to make it work correctly, you've to add the brackets as below:



          find . '(' -name '*.cpp' -o -name '*.h' ')' -exec echo {} ';'



          Remember: The parentheses must be quoted or escaped with a backslash to prevent them from being interpreted as special shell characters.




          Alternatively combine few extensions into one by using -regex:



          find . ! -regex ".*.(cpp|h)" -exec echo {} ;





          share|improve this answer































            1














            Try to surround your search criteria with brackets as such:



            find . ( -name "*.cpp" -o -name "*.h" ) -exec echo {} ;





            share|improve this answer





























              1














              Neither. It's the syntax of the options that is "wrong". find evalutates sequencially. Hence, it evaluates the first expression (-name "*.cpp") then encounters a -o flag. If the first expression is true, find will not continue evaluating the second one (-name "*.h" -exec echo {} ;), instead does nothing. You see, the whole part after -o is one expression. Therefore, this is only executed for files that match the second expression. That's why you see only the 1.h file, which passes only the second expression. See the find manpage:



                 expr1 -o expr2
              Or; expr2 is not evaluated if expr1 is true.


              Why is this useful? Consider the following:



              find /path -exec test_file_for_something {} -print ; -o -name "xyz" -exec ls -l {} ;


              In this find statement the file is given to test_file_for_something as a parameter. Now, depending on that commands return code the first expression is true (then -print is executed and it ends there) or false (then the second expression after the -o flag is evaluated). And if that one is true (the name is xyz), then -exec is executed.



              For your problem you can instead use this to group the elements together as one expression:



              find . ( -name "*.cpp" -o -name "*.h" ) -exec echo {} ;





              share|improve this answer





























                0














                That is the way find works with it's operators.



                See http://linux.die.net/man/1/find section OPERATORS




                OPERATORS



                Listed in order of decreasing precedence: ( expr ) Force precedence.
                Since parentheses are special to the shell, you will normally need to
                quote them. Many of the examples in this manual page use backslashes
                for this purpose: '(...)' instead of '(...)'. ! expr True if expr is
                false. This character will also usually need protection from
                interpretation by the shell.



                -not expr Same as ! expr, but not POSIX compliant. expr1 expr2 Two expressions in a row are taken to be joined with an implied "and";
                expr2 is not evaluated if expr1 is false. expr1 -a expr2 Same as expr1
                expr2. expr1 -and expr2 Same as expr1 expr2, but not POSIX compliant.
                expr1 -o expr2 Or; expr2 is not evaluated if expr1 is true. expr1 -or
                expr2 Same as expr1 -o expr2, but not POSIX compliant. expr1 , expr2
                List; both expr1 and expr2 are always evaluated. The value of expr1 is
                discarded; the value of the list is the value of expr2. The comma
                operator can be useful for searching for several different types of
                thing, but traversing the filesystem hierarchy only once. The -fprintf
                action can be used to list the various matched items into several
                different output files.




                This should give you the result you want:




                find . ( -name '*.cpp' -o -name '*.h' ) -exec echo {} ;




                Your command is doing this (command won't work, just to show you the logic):




                find . -name '*.cpp' (-o -name '*.h' -exec echo {} ;)







                share|improve this answer





















                  Your Answer








                  StackExchange.ready(function() {
                  var channelOptions = {
                  tags: "".split(" "),
                  id: "3"
                  };
                  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',
                  autoActivateHeartbeat: false,
                  convertImagesToLinks: true,
                  noModals: true,
                  showLowRepImageUploadWarning: true,
                  reputationToPostImages: 10,
                  bindNavPrevention: true,
                  postfix: "",
                  imageUploader: {
                  brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
                  contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
                  allowUrls: true
                  },
                  onDemand: true,
                  discardSelector: ".discard-answer"
                  ,immediatelyShowMarkdownHelp:true
                  });


                  }
                  });














                  draft saved

                  draft discarded


















                  StackExchange.ready(
                  function () {
                  StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fsuperuser.com%2fquestions%2f966227%2fwhy-does-find-in-linux-skip-expected-results-when-o-is-used%23new-answer', 'question_page');
                  }
                  );

                  Post as a guest















                  Required, but never shown

























                  4 Answers
                  4






                  active

                  oldest

                  votes








                  4 Answers
                  4






                  active

                  oldest

                  votes









                  active

                  oldest

                  votes






                  active

                  oldest

                  votes









                  1














                  I think once you used -or operator, then you've to keep it consistent in order to avoid ambiguous order of logical operations when you have multiple conditions connected using logical OR.



                  It seems the -exec part is grouped together with the second -name "*.h".



                  So in order to make it work correctly, you've to add the brackets as below:



                  find . '(' -name '*.cpp' -o -name '*.h' ')' -exec echo {} ';'



                  Remember: The parentheses must be quoted or escaped with a backslash to prevent them from being interpreted as special shell characters.




                  Alternatively combine few extensions into one by using -regex:



                  find . ! -regex ".*.(cpp|h)" -exec echo {} ;





                  share|improve this answer




























                    1














                    I think once you used -or operator, then you've to keep it consistent in order to avoid ambiguous order of logical operations when you have multiple conditions connected using logical OR.



                    It seems the -exec part is grouped together with the second -name "*.h".



                    So in order to make it work correctly, you've to add the brackets as below:



                    find . '(' -name '*.cpp' -o -name '*.h' ')' -exec echo {} ';'



                    Remember: The parentheses must be quoted or escaped with a backslash to prevent them from being interpreted as special shell characters.




                    Alternatively combine few extensions into one by using -regex:



                    find . ! -regex ".*.(cpp|h)" -exec echo {} ;





                    share|improve this answer


























                      1












                      1








                      1






                      I think once you used -or operator, then you've to keep it consistent in order to avoid ambiguous order of logical operations when you have multiple conditions connected using logical OR.



                      It seems the -exec part is grouped together with the second -name "*.h".



                      So in order to make it work correctly, you've to add the brackets as below:



                      find . '(' -name '*.cpp' -o -name '*.h' ')' -exec echo {} ';'



                      Remember: The parentheses must be quoted or escaped with a backslash to prevent them from being interpreted as special shell characters.




                      Alternatively combine few extensions into one by using -regex:



                      find . ! -regex ".*.(cpp|h)" -exec echo {} ;





                      share|improve this answer














                      I think once you used -or operator, then you've to keep it consistent in order to avoid ambiguous order of logical operations when you have multiple conditions connected using logical OR.



                      It seems the -exec part is grouped together with the second -name "*.h".



                      So in order to make it work correctly, you've to add the brackets as below:



                      find . '(' -name '*.cpp' -o -name '*.h' ')' -exec echo {} ';'



                      Remember: The parentheses must be quoted or escaped with a backslash to prevent them from being interpreted as special shell characters.




                      Alternatively combine few extensions into one by using -regex:



                      find . ! -regex ".*.(cpp|h)" -exec echo {} ;






                      share|improve this answer














                      share|improve this answer



                      share|improve this answer








                      edited Sep 26 '15 at 21:08

























                      answered Sep 2 '15 at 10:41









                      kenorb

                      10.7k1577111




                      10.7k1577111

























                          1














                          Try to surround your search criteria with brackets as such:



                          find . ( -name "*.cpp" -o -name "*.h" ) -exec echo {} ;





                          share|improve this answer


























                            1














                            Try to surround your search criteria with brackets as such:



                            find . ( -name "*.cpp" -o -name "*.h" ) -exec echo {} ;





                            share|improve this answer
























                              1












                              1








                              1






                              Try to surround your search criteria with brackets as such:



                              find . ( -name "*.cpp" -o -name "*.h" ) -exec echo {} ;





                              share|improve this answer












                              Try to surround your search criteria with brackets as such:



                              find . ( -name "*.cpp" -o -name "*.h" ) -exec echo {} ;






                              share|improve this answer












                              share|improve this answer



                              share|improve this answer










                              answered Sep 2 '15 at 10:41









                              Art Gertner

                              5,849113363




                              5,849113363























                                  1














                                  Neither. It's the syntax of the options that is "wrong". find evalutates sequencially. Hence, it evaluates the first expression (-name "*.cpp") then encounters a -o flag. If the first expression is true, find will not continue evaluating the second one (-name "*.h" -exec echo {} ;), instead does nothing. You see, the whole part after -o is one expression. Therefore, this is only executed for files that match the second expression. That's why you see only the 1.h file, which passes only the second expression. See the find manpage:



                                     expr1 -o expr2
                                  Or; expr2 is not evaluated if expr1 is true.


                                  Why is this useful? Consider the following:



                                  find /path -exec test_file_for_something {} -print ; -o -name "xyz" -exec ls -l {} ;


                                  In this find statement the file is given to test_file_for_something as a parameter. Now, depending on that commands return code the first expression is true (then -print is executed and it ends there) or false (then the second expression after the -o flag is evaluated). And if that one is true (the name is xyz), then -exec is executed.



                                  For your problem you can instead use this to group the elements together as one expression:



                                  find . ( -name "*.cpp" -o -name "*.h" ) -exec echo {} ;





                                  share|improve this answer


























                                    1














                                    Neither. It's the syntax of the options that is "wrong". find evalutates sequencially. Hence, it evaluates the first expression (-name "*.cpp") then encounters a -o flag. If the first expression is true, find will not continue evaluating the second one (-name "*.h" -exec echo {} ;), instead does nothing. You see, the whole part after -o is one expression. Therefore, this is only executed for files that match the second expression. That's why you see only the 1.h file, which passes only the second expression. See the find manpage:



                                       expr1 -o expr2
                                    Or; expr2 is not evaluated if expr1 is true.


                                    Why is this useful? Consider the following:



                                    find /path -exec test_file_for_something {} -print ; -o -name "xyz" -exec ls -l {} ;


                                    In this find statement the file is given to test_file_for_something as a parameter. Now, depending on that commands return code the first expression is true (then -print is executed and it ends there) or false (then the second expression after the -o flag is evaluated). And if that one is true (the name is xyz), then -exec is executed.



                                    For your problem you can instead use this to group the elements together as one expression:



                                    find . ( -name "*.cpp" -o -name "*.h" ) -exec echo {} ;





                                    share|improve this answer
























                                      1












                                      1








                                      1






                                      Neither. It's the syntax of the options that is "wrong". find evalutates sequencially. Hence, it evaluates the first expression (-name "*.cpp") then encounters a -o flag. If the first expression is true, find will not continue evaluating the second one (-name "*.h" -exec echo {} ;), instead does nothing. You see, the whole part after -o is one expression. Therefore, this is only executed for files that match the second expression. That's why you see only the 1.h file, which passes only the second expression. See the find manpage:



                                         expr1 -o expr2
                                      Or; expr2 is not evaluated if expr1 is true.


                                      Why is this useful? Consider the following:



                                      find /path -exec test_file_for_something {} -print ; -o -name "xyz" -exec ls -l {} ;


                                      In this find statement the file is given to test_file_for_something as a parameter. Now, depending on that commands return code the first expression is true (then -print is executed and it ends there) or false (then the second expression after the -o flag is evaluated). And if that one is true (the name is xyz), then -exec is executed.



                                      For your problem you can instead use this to group the elements together as one expression:



                                      find . ( -name "*.cpp" -o -name "*.h" ) -exec echo {} ;





                                      share|improve this answer












                                      Neither. It's the syntax of the options that is "wrong". find evalutates sequencially. Hence, it evaluates the first expression (-name "*.cpp") then encounters a -o flag. If the first expression is true, find will not continue evaluating the second one (-name "*.h" -exec echo {} ;), instead does nothing. You see, the whole part after -o is one expression. Therefore, this is only executed for files that match the second expression. That's why you see only the 1.h file, which passes only the second expression. See the find manpage:



                                         expr1 -o expr2
                                      Or; expr2 is not evaluated if expr1 is true.


                                      Why is this useful? Consider the following:



                                      find /path -exec test_file_for_something {} -print ; -o -name "xyz" -exec ls -l {} ;


                                      In this find statement the file is given to test_file_for_something as a parameter. Now, depending on that commands return code the first expression is true (then -print is executed and it ends there) or false (then the second expression after the -o flag is evaluated). And if that one is true (the name is xyz), then -exec is executed.



                                      For your problem you can instead use this to group the elements together as one expression:



                                      find . ( -name "*.cpp" -o -name "*.h" ) -exec echo {} ;






                                      share|improve this answer












                                      share|improve this answer



                                      share|improve this answer










                                      answered Sep 2 '15 at 11:03









                                      chaos

                                      3,40821026




                                      3,40821026























                                          0














                                          That is the way find works with it's operators.



                                          See http://linux.die.net/man/1/find section OPERATORS




                                          OPERATORS



                                          Listed in order of decreasing precedence: ( expr ) Force precedence.
                                          Since parentheses are special to the shell, you will normally need to
                                          quote them. Many of the examples in this manual page use backslashes
                                          for this purpose: '(...)' instead of '(...)'. ! expr True if expr is
                                          false. This character will also usually need protection from
                                          interpretation by the shell.



                                          -not expr Same as ! expr, but not POSIX compliant. expr1 expr2 Two expressions in a row are taken to be joined with an implied "and";
                                          expr2 is not evaluated if expr1 is false. expr1 -a expr2 Same as expr1
                                          expr2. expr1 -and expr2 Same as expr1 expr2, but not POSIX compliant.
                                          expr1 -o expr2 Or; expr2 is not evaluated if expr1 is true. expr1 -or
                                          expr2 Same as expr1 -o expr2, but not POSIX compliant. expr1 , expr2
                                          List; both expr1 and expr2 are always evaluated. The value of expr1 is
                                          discarded; the value of the list is the value of expr2. The comma
                                          operator can be useful for searching for several different types of
                                          thing, but traversing the filesystem hierarchy only once. The -fprintf
                                          action can be used to list the various matched items into several
                                          different output files.




                                          This should give you the result you want:




                                          find . ( -name '*.cpp' -o -name '*.h' ) -exec echo {} ;




                                          Your command is doing this (command won't work, just to show you the logic):




                                          find . -name '*.cpp' (-o -name '*.h' -exec echo {} ;)







                                          share|improve this answer


























                                            0














                                            That is the way find works with it's operators.



                                            See http://linux.die.net/man/1/find section OPERATORS




                                            OPERATORS



                                            Listed in order of decreasing precedence: ( expr ) Force precedence.
                                            Since parentheses are special to the shell, you will normally need to
                                            quote them. Many of the examples in this manual page use backslashes
                                            for this purpose: '(...)' instead of '(...)'. ! expr True if expr is
                                            false. This character will also usually need protection from
                                            interpretation by the shell.



                                            -not expr Same as ! expr, but not POSIX compliant. expr1 expr2 Two expressions in a row are taken to be joined with an implied "and";
                                            expr2 is not evaluated if expr1 is false. expr1 -a expr2 Same as expr1
                                            expr2. expr1 -and expr2 Same as expr1 expr2, but not POSIX compliant.
                                            expr1 -o expr2 Or; expr2 is not evaluated if expr1 is true. expr1 -or
                                            expr2 Same as expr1 -o expr2, but not POSIX compliant. expr1 , expr2
                                            List; both expr1 and expr2 are always evaluated. The value of expr1 is
                                            discarded; the value of the list is the value of expr2. The comma
                                            operator can be useful for searching for several different types of
                                            thing, but traversing the filesystem hierarchy only once. The -fprintf
                                            action can be used to list the various matched items into several
                                            different output files.




                                            This should give you the result you want:




                                            find . ( -name '*.cpp' -o -name '*.h' ) -exec echo {} ;




                                            Your command is doing this (command won't work, just to show you the logic):




                                            find . -name '*.cpp' (-o -name '*.h' -exec echo {} ;)







                                            share|improve this answer
























                                              0












                                              0








                                              0






                                              That is the way find works with it's operators.



                                              See http://linux.die.net/man/1/find section OPERATORS




                                              OPERATORS



                                              Listed in order of decreasing precedence: ( expr ) Force precedence.
                                              Since parentheses are special to the shell, you will normally need to
                                              quote them. Many of the examples in this manual page use backslashes
                                              for this purpose: '(...)' instead of '(...)'. ! expr True if expr is
                                              false. This character will also usually need protection from
                                              interpretation by the shell.



                                              -not expr Same as ! expr, but not POSIX compliant. expr1 expr2 Two expressions in a row are taken to be joined with an implied "and";
                                              expr2 is not evaluated if expr1 is false. expr1 -a expr2 Same as expr1
                                              expr2. expr1 -and expr2 Same as expr1 expr2, but not POSIX compliant.
                                              expr1 -o expr2 Or; expr2 is not evaluated if expr1 is true. expr1 -or
                                              expr2 Same as expr1 -o expr2, but not POSIX compliant. expr1 , expr2
                                              List; both expr1 and expr2 are always evaluated. The value of expr1 is
                                              discarded; the value of the list is the value of expr2. The comma
                                              operator can be useful for searching for several different types of
                                              thing, but traversing the filesystem hierarchy only once. The -fprintf
                                              action can be used to list the various matched items into several
                                              different output files.




                                              This should give you the result you want:




                                              find . ( -name '*.cpp' -o -name '*.h' ) -exec echo {} ;




                                              Your command is doing this (command won't work, just to show you the logic):




                                              find . -name '*.cpp' (-o -name '*.h' -exec echo {} ;)







                                              share|improve this answer












                                              That is the way find works with it's operators.



                                              See http://linux.die.net/man/1/find section OPERATORS




                                              OPERATORS



                                              Listed in order of decreasing precedence: ( expr ) Force precedence.
                                              Since parentheses are special to the shell, you will normally need to
                                              quote them. Many of the examples in this manual page use backslashes
                                              for this purpose: '(...)' instead of '(...)'. ! expr True if expr is
                                              false. This character will also usually need protection from
                                              interpretation by the shell.



                                              -not expr Same as ! expr, but not POSIX compliant. expr1 expr2 Two expressions in a row are taken to be joined with an implied "and";
                                              expr2 is not evaluated if expr1 is false. expr1 -a expr2 Same as expr1
                                              expr2. expr1 -and expr2 Same as expr1 expr2, but not POSIX compliant.
                                              expr1 -o expr2 Or; expr2 is not evaluated if expr1 is true. expr1 -or
                                              expr2 Same as expr1 -o expr2, but not POSIX compliant. expr1 , expr2
                                              List; both expr1 and expr2 are always evaluated. The value of expr1 is
                                              discarded; the value of the list is the value of expr2. The comma
                                              operator can be useful for searching for several different types of
                                              thing, but traversing the filesystem hierarchy only once. The -fprintf
                                              action can be used to list the various matched items into several
                                              different output files.




                                              This should give you the result you want:




                                              find . ( -name '*.cpp' -o -name '*.h' ) -exec echo {} ;




                                              Your command is doing this (command won't work, just to show you the logic):




                                              find . -name '*.cpp' (-o -name '*.h' -exec echo {} ;)








                                              share|improve this answer












                                              share|improve this answer



                                              share|improve this answer










                                              answered Sep 2 '15 at 10:43









                                              HoD

                                              1,640415




                                              1,640415






























                                                  draft saved

                                                  draft discarded




















































                                                  Thanks for contributing an answer to Super User!


                                                  • Please be sure to answer the question. Provide details and share your research!

                                                  But avoid



                                                  • Asking for help, clarification, or responding to other answers.

                                                  • Making statements based on opinion; back them up with references or personal experience.


                                                  To learn more, see our tips on writing great answers.





                                                  Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


                                                  Please pay close attention to the following guidance:


                                                  • Please be sure to answer the question. Provide details and share your research!

                                                  But avoid



                                                  • Asking for help, clarification, or responding to other answers.

                                                  • Making statements based on opinion; back them up with references or personal experience.


                                                  To learn more, see our tips on writing great answers.




                                                  draft saved


                                                  draft discarded














                                                  StackExchange.ready(
                                                  function () {
                                                  StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fsuperuser.com%2fquestions%2f966227%2fwhy-does-find-in-linux-skip-expected-results-when-o-is-used%23new-answer', 'question_page');
                                                  }
                                                  );

                                                  Post as a guest















                                                  Required, but never shown





















































                                                  Required, but never shown














                                                  Required, but never shown












                                                  Required, but never shown







                                                  Required, but never shown

































                                                  Required, but never shown














                                                  Required, but never shown












                                                  Required, but never shown







                                                  Required, but never shown







                                                  Popular posts from this blog

                                                  flock() on closed filehandle LOCK_FILE at /usr/bin/apt-mirror

                                                  Mangá

                                                  Eduardo VII do Reino Unido