`find` with multiple `-name` and `-exec` executes only the last matches of `-name`

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











up vote
54
down vote

favorite
21












When I'm using



find . -type f -name "*.htm*" -o -name "*.js*" -o -name "*.txt"



it finds all the types of file. But when I add -exec at the end:



find . -type f -name "*.htm*" -o -name "*.js*" -o -name "*.txt" -exec sh -c 'echo "$0"' ;



it seems it only prints .txt files. What am I doing wrong?



Note: using MINGW (Git Bash)










share|improve this question





















  • Hint: the first command will also print directories whose names match *.js* or *.txt.
    – Wildcard
    Sep 8 '17 at 0:00














up vote
54
down vote

favorite
21












When I'm using



find . -type f -name "*.htm*" -o -name "*.js*" -o -name "*.txt"



it finds all the types of file. But when I add -exec at the end:



find . -type f -name "*.htm*" -o -name "*.js*" -o -name "*.txt" -exec sh -c 'echo "$0"' ;



it seems it only prints .txt files. What am I doing wrong?



Note: using MINGW (Git Bash)










share|improve this question





















  • Hint: the first command will also print directories whose names match *.js* or *.txt.
    – Wildcard
    Sep 8 '17 at 0:00












up vote
54
down vote

favorite
21









up vote
54
down vote

favorite
21






21





When I'm using



find . -type f -name "*.htm*" -o -name "*.js*" -o -name "*.txt"



it finds all the types of file. But when I add -exec at the end:



find . -type f -name "*.htm*" -o -name "*.js*" -o -name "*.txt" -exec sh -c 'echo "$0"' ;



it seems it only prints .txt files. What am I doing wrong?



Note: using MINGW (Git Bash)










share|improve this question













When I'm using



find . -type f -name "*.htm*" -o -name "*.js*" -o -name "*.txt"



it finds all the types of file. But when I add -exec at the end:



find . -type f -name "*.htm*" -o -name "*.js*" -o -name "*.txt" -exec sh -c 'echo "$0"' ;



it seems it only prints .txt files. What am I doing wrong?



Note: using MINGW (Git Bash)







find






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked Nov 22 '13 at 10:52









jakub.g

91621015




91621015











  • Hint: the first command will also print directories whose names match *.js* or *.txt.
    – Wildcard
    Sep 8 '17 at 0:00
















  • Hint: the first command will also print directories whose names match *.js* or *.txt.
    – Wildcard
    Sep 8 '17 at 0:00















Hint: the first command will also print directories whose names match *.js* or *.txt.
– Wildcard
Sep 8 '17 at 0:00




Hint: the first command will also print directories whose names match *.js* or *.txt.
– Wildcard
Sep 8 '17 at 0:00










3 Answers
3






active

oldest

votes

















up vote
75
down vote



accepted











find . -type f -name "*.htm*" -o -name "*.js*" -o -name "*.txt"


is short for:




find . ( ( -type f -a -name "*.htm*" ) -o
( -name "*.js*" ) -o
( -name "*.txt" )
) -a -print


That is, because no action predicate is specified (only conditions), a -print action is implicitly added for the files that match the conditions.



(and, by the way, that would print non-regular .js files (the -type f only applies to .htm files)).



While:




find . -type f -name "*.htm*" -o -name "*.js*" -o -name "*.txt"
-exec sh -c 'echo "$0"' ;


is short for:




find . ( -type f -a -name "*.htm*" ) -o
( -name "*.js*" ) -o
( -name "*.txt" -a -exec sh -c 'echo "$0"' ; )


For find (like in many languages), AND (-a; implicit when omitted) has precedence over OR (-o), and adding an explicit action predicate (here -exec) cancels the -print implicit action seen above. Here, you want:



find . -type f ( -name "*.htm*" -o -name "*.js*" -o -name "*.txt" ) 
-exec sh -c 'echo "$0"' ;


Or:



find . -type f ( -name "*.htm*" -o -name "*.js*" -o -name "*.txt" ) -exec sh -c '
for i do
echo "$i"
done' sh +


To avoid running one sh per file.






share|improve this answer






















  • In some of those sh -c uses, you need to add the zeroth argument for sh (though in others you included it already).
    – James Youngman
    Dec 9 '13 at 23:14










  • That's a great answer!
    – Marinos An
    Feb 28 at 21:05

















up vote
22
down vote













It is the implied brackets. Add explicit brackets. ( )



find . -type f ( -name "*.htm*" -o -name "*.js*" -o -name "*.txt" ) -exec sh -c 'echo "$0"' ;


or using xargs ( I like xargs I find it easier, but apparently not as portable).



find . -type f ( -name "*.htm*" -o -name "*.js*" -o -name "*.txt" ) -print0 | xargs -0 -n1 echo





share|improve this answer





























    up vote
    0
    down vote













    Remember you can always add the "&&" like below...



    find -name "*.html" && find -name "*.js" && find -name "*.txt"





    share|improve this answer
















    • 2




      This does not answer the question as there's no -exec action. Also, running multiple find commands to traverse the same directory tree is inefficient.
      – Anthony Geoghegan
      Sep 12 at 8:35










    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: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: null,
    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%2funix.stackexchange.com%2fquestions%2f102191%2ffind-with-multiple-name-and-exec-executes-only-the-last-matches-of-nam%23new-answer', 'question_page');

    );

    Post as a guest






























    3 Answers
    3






    active

    oldest

    votes








    3 Answers
    3






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes








    up vote
    75
    down vote



    accepted











    find . -type f -name "*.htm*" -o -name "*.js*" -o -name "*.txt"


    is short for:




    find . ( ( -type f -a -name "*.htm*" ) -o
    ( -name "*.js*" ) -o
    ( -name "*.txt" )
    ) -a -print


    That is, because no action predicate is specified (only conditions), a -print action is implicitly added for the files that match the conditions.



    (and, by the way, that would print non-regular .js files (the -type f only applies to .htm files)).



    While:




    find . -type f -name "*.htm*" -o -name "*.js*" -o -name "*.txt"
    -exec sh -c 'echo "$0"' ;


    is short for:




    find . ( -type f -a -name "*.htm*" ) -o
    ( -name "*.js*" ) -o
    ( -name "*.txt" -a -exec sh -c 'echo "$0"' ; )


    For find (like in many languages), AND (-a; implicit when omitted) has precedence over OR (-o), and adding an explicit action predicate (here -exec) cancels the -print implicit action seen above. Here, you want:



    find . -type f ( -name "*.htm*" -o -name "*.js*" -o -name "*.txt" ) 
    -exec sh -c 'echo "$0"' ;


    Or:



    find . -type f ( -name "*.htm*" -o -name "*.js*" -o -name "*.txt" ) -exec sh -c '
    for i do
    echo "$i"
    done' sh +


    To avoid running one sh per file.






    share|improve this answer






















    • In some of those sh -c uses, you need to add the zeroth argument for sh (though in others you included it already).
      – James Youngman
      Dec 9 '13 at 23:14










    • That's a great answer!
      – Marinos An
      Feb 28 at 21:05














    up vote
    75
    down vote



    accepted











    find . -type f -name "*.htm*" -o -name "*.js*" -o -name "*.txt"


    is short for:




    find . ( ( -type f -a -name "*.htm*" ) -o
    ( -name "*.js*" ) -o
    ( -name "*.txt" )
    ) -a -print


    That is, because no action predicate is specified (only conditions), a -print action is implicitly added for the files that match the conditions.



    (and, by the way, that would print non-regular .js files (the -type f only applies to .htm files)).



    While:




    find . -type f -name "*.htm*" -o -name "*.js*" -o -name "*.txt"
    -exec sh -c 'echo "$0"' ;


    is short for:




    find . ( -type f -a -name "*.htm*" ) -o
    ( -name "*.js*" ) -o
    ( -name "*.txt" -a -exec sh -c 'echo "$0"' ; )


    For find (like in many languages), AND (-a; implicit when omitted) has precedence over OR (-o), and adding an explicit action predicate (here -exec) cancels the -print implicit action seen above. Here, you want:



    find . -type f ( -name "*.htm*" -o -name "*.js*" -o -name "*.txt" ) 
    -exec sh -c 'echo "$0"' ;


    Or:



    find . -type f ( -name "*.htm*" -o -name "*.js*" -o -name "*.txt" ) -exec sh -c '
    for i do
    echo "$i"
    done' sh +


    To avoid running one sh per file.






    share|improve this answer






















    • In some of those sh -c uses, you need to add the zeroth argument for sh (though in others you included it already).
      – James Youngman
      Dec 9 '13 at 23:14










    • That's a great answer!
      – Marinos An
      Feb 28 at 21:05












    up vote
    75
    down vote



    accepted







    up vote
    75
    down vote



    accepted







    find . -type f -name "*.htm*" -o -name "*.js*" -o -name "*.txt"


    is short for:




    find . ( ( -type f -a -name "*.htm*" ) -o
    ( -name "*.js*" ) -o
    ( -name "*.txt" )
    ) -a -print


    That is, because no action predicate is specified (only conditions), a -print action is implicitly added for the files that match the conditions.



    (and, by the way, that would print non-regular .js files (the -type f only applies to .htm files)).



    While:




    find . -type f -name "*.htm*" -o -name "*.js*" -o -name "*.txt"
    -exec sh -c 'echo "$0"' ;


    is short for:




    find . ( -type f -a -name "*.htm*" ) -o
    ( -name "*.js*" ) -o
    ( -name "*.txt" -a -exec sh -c 'echo "$0"' ; )


    For find (like in many languages), AND (-a; implicit when omitted) has precedence over OR (-o), and adding an explicit action predicate (here -exec) cancels the -print implicit action seen above. Here, you want:



    find . -type f ( -name "*.htm*" -o -name "*.js*" -o -name "*.txt" ) 
    -exec sh -c 'echo "$0"' ;


    Or:



    find . -type f ( -name "*.htm*" -o -name "*.js*" -o -name "*.txt" ) -exec sh -c '
    for i do
    echo "$i"
    done' sh +


    To avoid running one sh per file.






    share|improve this answer















    find . -type f -name "*.htm*" -o -name "*.js*" -o -name "*.txt"


    is short for:




    find . ( ( -type f -a -name "*.htm*" ) -o
    ( -name "*.js*" ) -o
    ( -name "*.txt" )
    ) -a -print


    That is, because no action predicate is specified (only conditions), a -print action is implicitly added for the files that match the conditions.



    (and, by the way, that would print non-regular .js files (the -type f only applies to .htm files)).



    While:




    find . -type f -name "*.htm*" -o -name "*.js*" -o -name "*.txt"
    -exec sh -c 'echo "$0"' ;


    is short for:




    find . ( -type f -a -name "*.htm*" ) -o
    ( -name "*.js*" ) -o
    ( -name "*.txt" -a -exec sh -c 'echo "$0"' ; )


    For find (like in many languages), AND (-a; implicit when omitted) has precedence over OR (-o), and adding an explicit action predicate (here -exec) cancels the -print implicit action seen above. Here, you want:



    find . -type f ( -name "*.htm*" -o -name "*.js*" -o -name "*.txt" ) 
    -exec sh -c 'echo "$0"' ;


    Or:



    find . -type f ( -name "*.htm*" -o -name "*.js*" -o -name "*.txt" ) -exec sh -c '
    for i do
    echo "$i"
    done' sh +


    To avoid running one sh per file.







    share|improve this answer














    share|improve this answer



    share|improve this answer








    edited 14 mins ago

























    answered Nov 22 '13 at 12:34









    Stéphane Chazelas

    292k54544884




    292k54544884











    • In some of those sh -c uses, you need to add the zeroth argument for sh (though in others you included it already).
      – James Youngman
      Dec 9 '13 at 23:14










    • That's a great answer!
      – Marinos An
      Feb 28 at 21:05
















    • In some of those sh -c uses, you need to add the zeroth argument for sh (though in others you included it already).
      – James Youngman
      Dec 9 '13 at 23:14










    • That's a great answer!
      – Marinos An
      Feb 28 at 21:05















    In some of those sh -c uses, you need to add the zeroth argument for sh (though in others you included it already).
    – James Youngman
    Dec 9 '13 at 23:14




    In some of those sh -c uses, you need to add the zeroth argument for sh (though in others you included it already).
    – James Youngman
    Dec 9 '13 at 23:14












    That's a great answer!
    – Marinos An
    Feb 28 at 21:05




    That's a great answer!
    – Marinos An
    Feb 28 at 21:05












    up vote
    22
    down vote













    It is the implied brackets. Add explicit brackets. ( )



    find . -type f ( -name "*.htm*" -o -name "*.js*" -o -name "*.txt" ) -exec sh -c 'echo "$0"' ;


    or using xargs ( I like xargs I find it easier, but apparently not as portable).



    find . -type f ( -name "*.htm*" -o -name "*.js*" -o -name "*.txt" ) -print0 | xargs -0 -n1 echo





    share|improve this answer


























      up vote
      22
      down vote













      It is the implied brackets. Add explicit brackets. ( )



      find . -type f ( -name "*.htm*" -o -name "*.js*" -o -name "*.txt" ) -exec sh -c 'echo "$0"' ;


      or using xargs ( I like xargs I find it easier, but apparently not as portable).



      find . -type f ( -name "*.htm*" -o -name "*.js*" -o -name "*.txt" ) -print0 | xargs -0 -n1 echo





      share|improve this answer
























        up vote
        22
        down vote










        up vote
        22
        down vote









        It is the implied brackets. Add explicit brackets. ( )



        find . -type f ( -name "*.htm*" -o -name "*.js*" -o -name "*.txt" ) -exec sh -c 'echo "$0"' ;


        or using xargs ( I like xargs I find it easier, but apparently not as portable).



        find . -type f ( -name "*.htm*" -o -name "*.js*" -o -name "*.txt" ) -print0 | xargs -0 -n1 echo





        share|improve this answer














        It is the implied brackets. Add explicit brackets. ( )



        find . -type f ( -name "*.htm*" -o -name "*.js*" -o -name "*.txt" ) -exec sh -c 'echo "$0"' ;


        or using xargs ( I like xargs I find it easier, but apparently not as portable).



        find . -type f ( -name "*.htm*" -o -name "*.js*" -o -name "*.txt" ) -print0 | xargs -0 -n1 echo






        share|improve this answer














        share|improve this answer



        share|improve this answer








        edited Jul 1 '14 at 10:14

























        answered Nov 22 '13 at 11:31









        ctrl-alt-delor

        9,60331950




        9,60331950




















            up vote
            0
            down vote













            Remember you can always add the "&&" like below...



            find -name "*.html" && find -name "*.js" && find -name "*.txt"





            share|improve this answer
















            • 2




              This does not answer the question as there's no -exec action. Also, running multiple find commands to traverse the same directory tree is inefficient.
              – Anthony Geoghegan
              Sep 12 at 8:35














            up vote
            0
            down vote













            Remember you can always add the "&&" like below...



            find -name "*.html" && find -name "*.js" && find -name "*.txt"





            share|improve this answer
















            • 2




              This does not answer the question as there's no -exec action. Also, running multiple find commands to traverse the same directory tree is inefficient.
              – Anthony Geoghegan
              Sep 12 at 8:35












            up vote
            0
            down vote










            up vote
            0
            down vote









            Remember you can always add the "&&" like below...



            find -name "*.html" && find -name "*.js" && find -name "*.txt"





            share|improve this answer












            Remember you can always add the "&&" like below...



            find -name "*.html" && find -name "*.js" && find -name "*.txt"






            share|improve this answer












            share|improve this answer



            share|improve this answer










            answered Sep 12 at 8:20









            kierzo

            1




            1







            • 2




              This does not answer the question as there's no -exec action. Also, running multiple find commands to traverse the same directory tree is inefficient.
              – Anthony Geoghegan
              Sep 12 at 8:35












            • 2




              This does not answer the question as there's no -exec action. Also, running multiple find commands to traverse the same directory tree is inefficient.
              – Anthony Geoghegan
              Sep 12 at 8:35







            2




            2




            This does not answer the question as there's no -exec action. Also, running multiple find commands to traverse the same directory tree is inefficient.
            – Anthony Geoghegan
            Sep 12 at 8:35




            This does not answer the question as there's no -exec action. Also, running multiple find commands to traverse the same directory tree is inefficient.
            – Anthony Geoghegan
            Sep 12 at 8:35

















             

            draft saved


            draft discarded















































             


            draft saved


            draft discarded














            StackExchange.ready(
            function ()
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f102191%2ffind-with-multiple-name-and-exec-executes-only-the-last-matches-of-nam%23new-answer', 'question_page');

            );

            Post as a guest