find exec '{}' not available after >











up vote
6
down vote

favorite
2












Exec allows us to either pass all arguments at once with {} + or to pass them one by one with {} ;



Now let's say I want to rename all jpeg, no problem doing this:



find . ( -name '*.jpg' -o -name '*.jpeg' ) -exec mv '{}' '{}'.new ;


But if I need to redirect output, '{}' isn't accessible after redirection.



find . ( -name '*.jpg' -o -name '*.jpeg' ) -exec cjpeg -quality 80 '{}' > optimized_'{}' ;


This wouldn't work. I'd have to use a for loop, storing find's output into a variable before using it. Let's admit it, it's cumbersome.



for f in `find . ( -name '*.jpg' -o -name '*.jpeg' )`; do cjpeg -quality 80 $f > optimized_$f; done;


So is there a better way?










share|improve this question
























  • Isn't there a > missing in the third code sample?
    – choroba
    2 days ago






  • 1




    Even your first line is nonstandard and thus non-portable. Try to avoid command lines where {} appears in a longer strings as such strings are typically not expanded.
    – schily
    2 days ago










  • That first example does not do what you say.
    – ctrl-alt-delor
    2 days ago






  • 1




    You have fixed your question: I would no-longer change it.
    – ctrl-alt-delor
    2 days ago






  • 1




    For what it's worth, the primary reason that your redirection does not work as you wanted is that it is handled by the shell from which you launch find, once, and applied to the find command itself. The {} has no special meaning in that context. The redirection is not an argument to find, and it certainly is not part of the -exec clause.
    – John Bollinger
    2 days ago















up vote
6
down vote

favorite
2












Exec allows us to either pass all arguments at once with {} + or to pass them one by one with {} ;



Now let's say I want to rename all jpeg, no problem doing this:



find . ( -name '*.jpg' -o -name '*.jpeg' ) -exec mv '{}' '{}'.new ;


But if I need to redirect output, '{}' isn't accessible after redirection.



find . ( -name '*.jpg' -o -name '*.jpeg' ) -exec cjpeg -quality 80 '{}' > optimized_'{}' ;


This wouldn't work. I'd have to use a for loop, storing find's output into a variable before using it. Let's admit it, it's cumbersome.



for f in `find . ( -name '*.jpg' -o -name '*.jpeg' )`; do cjpeg -quality 80 $f > optimized_$f; done;


So is there a better way?










share|improve this question
























  • Isn't there a > missing in the third code sample?
    – choroba
    2 days ago






  • 1




    Even your first line is nonstandard and thus non-portable. Try to avoid command lines where {} appears in a longer strings as such strings are typically not expanded.
    – schily
    2 days ago










  • That first example does not do what you say.
    – ctrl-alt-delor
    2 days ago






  • 1




    You have fixed your question: I would no-longer change it.
    – ctrl-alt-delor
    2 days ago






  • 1




    For what it's worth, the primary reason that your redirection does not work as you wanted is that it is handled by the shell from which you launch find, once, and applied to the find command itself. The {} has no special meaning in that context. The redirection is not an argument to find, and it certainly is not part of the -exec clause.
    – John Bollinger
    2 days ago













up vote
6
down vote

favorite
2









up vote
6
down vote

favorite
2






2





Exec allows us to either pass all arguments at once with {} + or to pass them one by one with {} ;



Now let's say I want to rename all jpeg, no problem doing this:



find . ( -name '*.jpg' -o -name '*.jpeg' ) -exec mv '{}' '{}'.new ;


But if I need to redirect output, '{}' isn't accessible after redirection.



find . ( -name '*.jpg' -o -name '*.jpeg' ) -exec cjpeg -quality 80 '{}' > optimized_'{}' ;


This wouldn't work. I'd have to use a for loop, storing find's output into a variable before using it. Let's admit it, it's cumbersome.



for f in `find . ( -name '*.jpg' -o -name '*.jpeg' )`; do cjpeg -quality 80 $f > optimized_$f; done;


So is there a better way?










share|improve this question















Exec allows us to either pass all arguments at once with {} + or to pass them one by one with {} ;



Now let's say I want to rename all jpeg, no problem doing this:



find . ( -name '*.jpg' -o -name '*.jpeg' ) -exec mv '{}' '{}'.new ;


But if I need to redirect output, '{}' isn't accessible after redirection.



find . ( -name '*.jpg' -o -name '*.jpeg' ) -exec cjpeg -quality 80 '{}' > optimized_'{}' ;


This wouldn't work. I'd have to use a for loop, storing find's output into a variable before using it. Let's admit it, it's cumbersome.



for f in `find . ( -name '*.jpg' -o -name '*.jpeg' )`; do cjpeg -quality 80 $f > optimized_$f; done;


So is there a better way?







bash find






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited 2 days ago

























asked 2 days ago









Buzut

1335




1335












  • Isn't there a > missing in the third code sample?
    – choroba
    2 days ago






  • 1




    Even your first line is nonstandard and thus non-portable. Try to avoid command lines where {} appears in a longer strings as such strings are typically not expanded.
    – schily
    2 days ago










  • That first example does not do what you say.
    – ctrl-alt-delor
    2 days ago






  • 1




    You have fixed your question: I would no-longer change it.
    – ctrl-alt-delor
    2 days ago






  • 1




    For what it's worth, the primary reason that your redirection does not work as you wanted is that it is handled by the shell from which you launch find, once, and applied to the find command itself. The {} has no special meaning in that context. The redirection is not an argument to find, and it certainly is not part of the -exec clause.
    – John Bollinger
    2 days ago


















  • Isn't there a > missing in the third code sample?
    – choroba
    2 days ago






  • 1




    Even your first line is nonstandard and thus non-portable. Try to avoid command lines where {} appears in a longer strings as such strings are typically not expanded.
    – schily
    2 days ago










  • That first example does not do what you say.
    – ctrl-alt-delor
    2 days ago






  • 1




    You have fixed your question: I would no-longer change it.
    – ctrl-alt-delor
    2 days ago






  • 1




    For what it's worth, the primary reason that your redirection does not work as you wanted is that it is handled by the shell from which you launch find, once, and applied to the find command itself. The {} has no special meaning in that context. The redirection is not an argument to find, and it certainly is not part of the -exec clause.
    – John Bollinger
    2 days ago
















Isn't there a > missing in the third code sample?
– choroba
2 days ago




Isn't there a > missing in the third code sample?
– choroba
2 days ago




1




1




Even your first line is nonstandard and thus non-portable. Try to avoid command lines where {} appears in a longer strings as such strings are typically not expanded.
– schily
2 days ago




Even your first line is nonstandard and thus non-portable. Try to avoid command lines where {} appears in a longer strings as such strings are typically not expanded.
– schily
2 days ago












That first example does not do what you say.
– ctrl-alt-delor
2 days ago




That first example does not do what you say.
– ctrl-alt-delor
2 days ago




1




1




You have fixed your question: I would no-longer change it.
– ctrl-alt-delor
2 days ago




You have fixed your question: I would no-longer change it.
– ctrl-alt-delor
2 days ago




1




1




For what it's worth, the primary reason that your redirection does not work as you wanted is that it is handled by the shell from which you launch find, once, and applied to the find command itself. The {} has no special meaning in that context. The redirection is not an argument to find, and it certainly is not part of the -exec clause.
– John Bollinger
2 days ago




For what it's worth, the primary reason that your redirection does not work as you wanted is that it is handled by the shell from which you launch find, once, and applied to the find command itself. The {} has no special meaning in that context. The redirection is not an argument to find, and it certainly is not part of the -exec clause.
– John Bollinger
2 days ago










5 Answers
5






active

oldest

votes

















up vote
11
down vote



accepted










You could use bash -c within the find -exec command and use the positional parameter with the bash command:



find . ( -name '*.jpg' -o -name '*.jpeg' ) -exec bash -c 'cjpeg -quality 80 "$1" > "$(dirname "$1")/optimized_$(basename "$1")"' sh {} ;


That way {} is provided with $1.



The sh before the {} tells the inner shell its "name", the string used here is used in e.g. error messages. This is discussed more in this answer on stackoverflow.






share|improve this answer






























    up vote
    8
    down vote













    You have an answer(https://unix.stackexchange.com/a/481687/4778), but here is why.



    The redirection >, and also pipes |, and $ expansion, are all done by the shell before the command is executed. Therefore stdout is redirected to optimized_{}, before find is started.






    share|improve this answer




























      up vote
      3
      down vote













      The redirection needs to be quoted to avoid that the present shell interprets it.

      But quoting it will also avoid the output of the command to be redirected.

      The known solution to this is to call a shell:



      find . -name '*.jpg' -exec sh -c 'echo "$1" >"$1".new' called_shell '{}' ;


      In this case, the redirection (>) is quoted on the present shell and works correctly inside the called shell. The called_shell is used as the $0 parameter (the name) of the child shell (sh).



      That works well if a suffix is added the name of the file, but not if you use a prefix. For a prefix to work you need both to remove the ./ that find prepend to filenames with ${1#./} and to use the -execdir option.



      You may (or may not) want to use the -iname option so that files named *.JPG or *.JpG or other variations are also included.



      find . ( -iname '*.jpg' -o -iname '*.jpeg' ) -execdir sh -c '
      cjpeg -quality 80 "$1" > optimized_"${1#./}"
      ' called_shell '{}' ;


      And, you may (or may not) also want to call the shell once per directory instead of once per file by adding a loop (for f do … ; done) and a + at the end:



      find . ( -iname '*.jpg' -o -iname '*.jpeg' ) -execdir sh -c '
      for f; do cjpeg -quality 80 "$f" > optimized_"${f#./}"; done
      ' called_shell '{}' +


      And, finally, as cjpeg is able to directly write to a file, the redirection could be avoided as:



      find . ( -iname '*.jpg' -o -iname '*.jpeg' ) -execdir sh -c '
      for f; do cjpeg -quality 80 "$f" -outfile optimized_"${f#./}"; done
      ' called_shell '{}' +





      share|improve this answer






























        up vote
        3
        down vote













        cjpeg has an option that lets you write to a named file, rather than standard output. If your version of find supports the -execdir option, you can take advantage of that to make the redirection unnecessary.



        find . ( -name '*.jpg' -o -name '*.jpeg' ) 
        -execdir cjpeg -quality 80 -outfile optimized_'{}' '{}' ;


        Note: this actually assumes the BSD version of find, which appears to strip the leading ./ from the file name when exanding to {}. (Or conversely, GNU find adds ./ to the name. There's no standard to say which behavior is "right".)






        share|improve this answer























        • If your find supports -execdir, you can use that instead of -exec. It causes the command to run in the directory where the file was found, and {} will become aa.jpg instead of ./t2/aa.jpg.
          – chepner
          2 days ago












        • Still in error: cjpeg: can't open optimized_./aa.jpg.
          – Isaac
          2 days ago










        • Hm, that appears to be a difference between GNU find and BSD find. (The perils of using non-standard extensions.)
          – chepner
          2 days ago












        • A filename without a leading ./ seems to be more prone to errors. A reasonable solution is proposed in this answer.
          – Isaac
          2 days ago


















        up vote
        1
        down vote













        Create a script cjq80:



        #!/bin/bash
        cjpeg -quality 80 "$1" > "${1%/*}"/optimized_"${1##*/}"


        Make it executable



        chmod u+x cjq80


        And use it in -exec:



        find . ( -name '*.jpg' -o -name '*.jpeg' ) -exec cjq80 '{}' ;





        share|improve this answer























        • I had though about this, but it's not very handy. Especially as I had to incorporate this in a build process
          – Buzut
          2 days ago










        • Just add the script to other build scripts, I find it more readable than doubly nested bash -c.
          – choroba
          2 days ago










        • Well, it's a matter of taste. Now every option is specified so if someone encounters the same issue, he'll choose for himself :)
          – Buzut
          2 days ago










        • @mosvy: Thanks, fixed.
          – choroba
          yesterday











        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%2f481685%2ffind-exec-not-available-after%23new-answer', 'question_page');
        }
        );

        Post as a guest















        Required, but never shown

























        5 Answers
        5






        active

        oldest

        votes








        5 Answers
        5






        active

        oldest

        votes









        active

        oldest

        votes






        active

        oldest

        votes








        up vote
        11
        down vote



        accepted










        You could use bash -c within the find -exec command and use the positional parameter with the bash command:



        find . ( -name '*.jpg' -o -name '*.jpeg' ) -exec bash -c 'cjpeg -quality 80 "$1" > "$(dirname "$1")/optimized_$(basename "$1")"' sh {} ;


        That way {} is provided with $1.



        The sh before the {} tells the inner shell its "name", the string used here is used in e.g. error messages. This is discussed more in this answer on stackoverflow.






        share|improve this answer



























          up vote
          11
          down vote



          accepted










          You could use bash -c within the find -exec command and use the positional parameter with the bash command:



          find . ( -name '*.jpg' -o -name '*.jpeg' ) -exec bash -c 'cjpeg -quality 80 "$1" > "$(dirname "$1")/optimized_$(basename "$1")"' sh {} ;


          That way {} is provided with $1.



          The sh before the {} tells the inner shell its "name", the string used here is used in e.g. error messages. This is discussed more in this answer on stackoverflow.






          share|improve this answer

























            up vote
            11
            down vote



            accepted







            up vote
            11
            down vote



            accepted






            You could use bash -c within the find -exec command and use the positional parameter with the bash command:



            find . ( -name '*.jpg' -o -name '*.jpeg' ) -exec bash -c 'cjpeg -quality 80 "$1" > "$(dirname "$1")/optimized_$(basename "$1")"' sh {} ;


            That way {} is provided with $1.



            The sh before the {} tells the inner shell its "name", the string used here is used in e.g. error messages. This is discussed more in this answer on stackoverflow.






            share|improve this answer














            You could use bash -c within the find -exec command and use the positional parameter with the bash command:



            find . ( -name '*.jpg' -o -name '*.jpeg' ) -exec bash -c 'cjpeg -quality 80 "$1" > "$(dirname "$1")/optimized_$(basename "$1")"' sh {} ;


            That way {} is provided with $1.



            The sh before the {} tells the inner shell its "name", the string used here is used in e.g. error messages. This is discussed more in this answer on stackoverflow.







            share|improve this answer














            share|improve this answer



            share|improve this answer








            edited 2 days ago

























            answered 2 days ago









            oliv

            1,626311




            1,626311
























                up vote
                8
                down vote













                You have an answer(https://unix.stackexchange.com/a/481687/4778), but here is why.



                The redirection >, and also pipes |, and $ expansion, are all done by the shell before the command is executed. Therefore stdout is redirected to optimized_{}, before find is started.






                share|improve this answer

























                  up vote
                  8
                  down vote













                  You have an answer(https://unix.stackexchange.com/a/481687/4778), but here is why.



                  The redirection >, and also pipes |, and $ expansion, are all done by the shell before the command is executed. Therefore stdout is redirected to optimized_{}, before find is started.






                  share|improve this answer























                    up vote
                    8
                    down vote










                    up vote
                    8
                    down vote









                    You have an answer(https://unix.stackexchange.com/a/481687/4778), but here is why.



                    The redirection >, and also pipes |, and $ expansion, are all done by the shell before the command is executed. Therefore stdout is redirected to optimized_{}, before find is started.






                    share|improve this answer












                    You have an answer(https://unix.stackexchange.com/a/481687/4778), but here is why.



                    The redirection >, and also pipes |, and $ expansion, are all done by the shell before the command is executed. Therefore stdout is redirected to optimized_{}, before find is started.







                    share|improve this answer












                    share|improve this answer



                    share|improve this answer










                    answered 2 days ago









                    ctrl-alt-delor

                    9,87031954




                    9,87031954






















                        up vote
                        3
                        down vote













                        The redirection needs to be quoted to avoid that the present shell interprets it.

                        But quoting it will also avoid the output of the command to be redirected.

                        The known solution to this is to call a shell:



                        find . -name '*.jpg' -exec sh -c 'echo "$1" >"$1".new' called_shell '{}' ;


                        In this case, the redirection (>) is quoted on the present shell and works correctly inside the called shell. The called_shell is used as the $0 parameter (the name) of the child shell (sh).



                        That works well if a suffix is added the name of the file, but not if you use a prefix. For a prefix to work you need both to remove the ./ that find prepend to filenames with ${1#./} and to use the -execdir option.



                        You may (or may not) want to use the -iname option so that files named *.JPG or *.JpG or other variations are also included.



                        find . ( -iname '*.jpg' -o -iname '*.jpeg' ) -execdir sh -c '
                        cjpeg -quality 80 "$1" > optimized_"${1#./}"
                        ' called_shell '{}' ;


                        And, you may (or may not) also want to call the shell once per directory instead of once per file by adding a loop (for f do … ; done) and a + at the end:



                        find . ( -iname '*.jpg' -o -iname '*.jpeg' ) -execdir sh -c '
                        for f; do cjpeg -quality 80 "$f" > optimized_"${f#./}"; done
                        ' called_shell '{}' +


                        And, finally, as cjpeg is able to directly write to a file, the redirection could be avoided as:



                        find . ( -iname '*.jpg' -o -iname '*.jpeg' ) -execdir sh -c '
                        for f; do cjpeg -quality 80 "$f" -outfile optimized_"${f#./}"; done
                        ' called_shell '{}' +





                        share|improve this answer



























                          up vote
                          3
                          down vote













                          The redirection needs to be quoted to avoid that the present shell interprets it.

                          But quoting it will also avoid the output of the command to be redirected.

                          The known solution to this is to call a shell:



                          find . -name '*.jpg' -exec sh -c 'echo "$1" >"$1".new' called_shell '{}' ;


                          In this case, the redirection (>) is quoted on the present shell and works correctly inside the called shell. The called_shell is used as the $0 parameter (the name) of the child shell (sh).



                          That works well if a suffix is added the name of the file, but not if you use a prefix. For a prefix to work you need both to remove the ./ that find prepend to filenames with ${1#./} and to use the -execdir option.



                          You may (or may not) want to use the -iname option so that files named *.JPG or *.JpG or other variations are also included.



                          find . ( -iname '*.jpg' -o -iname '*.jpeg' ) -execdir sh -c '
                          cjpeg -quality 80 "$1" > optimized_"${1#./}"
                          ' called_shell '{}' ;


                          And, you may (or may not) also want to call the shell once per directory instead of once per file by adding a loop (for f do … ; done) and a + at the end:



                          find . ( -iname '*.jpg' -o -iname '*.jpeg' ) -execdir sh -c '
                          for f; do cjpeg -quality 80 "$f" > optimized_"${f#./}"; done
                          ' called_shell '{}' +


                          And, finally, as cjpeg is able to directly write to a file, the redirection could be avoided as:



                          find . ( -iname '*.jpg' -o -iname '*.jpeg' ) -execdir sh -c '
                          for f; do cjpeg -quality 80 "$f" -outfile optimized_"${f#./}"; done
                          ' called_shell '{}' +





                          share|improve this answer

























                            up vote
                            3
                            down vote










                            up vote
                            3
                            down vote









                            The redirection needs to be quoted to avoid that the present shell interprets it.

                            But quoting it will also avoid the output of the command to be redirected.

                            The known solution to this is to call a shell:



                            find . -name '*.jpg' -exec sh -c 'echo "$1" >"$1".new' called_shell '{}' ;


                            In this case, the redirection (>) is quoted on the present shell and works correctly inside the called shell. The called_shell is used as the $0 parameter (the name) of the child shell (sh).



                            That works well if a suffix is added the name of the file, but not if you use a prefix. For a prefix to work you need both to remove the ./ that find prepend to filenames with ${1#./} and to use the -execdir option.



                            You may (or may not) want to use the -iname option so that files named *.JPG or *.JpG or other variations are also included.



                            find . ( -iname '*.jpg' -o -iname '*.jpeg' ) -execdir sh -c '
                            cjpeg -quality 80 "$1" > optimized_"${1#./}"
                            ' called_shell '{}' ;


                            And, you may (or may not) also want to call the shell once per directory instead of once per file by adding a loop (for f do … ; done) and a + at the end:



                            find . ( -iname '*.jpg' -o -iname '*.jpeg' ) -execdir sh -c '
                            for f; do cjpeg -quality 80 "$f" > optimized_"${f#./}"; done
                            ' called_shell '{}' +


                            And, finally, as cjpeg is able to directly write to a file, the redirection could be avoided as:



                            find . ( -iname '*.jpg' -o -iname '*.jpeg' ) -execdir sh -c '
                            for f; do cjpeg -quality 80 "$f" -outfile optimized_"${f#./}"; done
                            ' called_shell '{}' +





                            share|improve this answer














                            The redirection needs to be quoted to avoid that the present shell interprets it.

                            But quoting it will also avoid the output of the command to be redirected.

                            The known solution to this is to call a shell:



                            find . -name '*.jpg' -exec sh -c 'echo "$1" >"$1".new' called_shell '{}' ;


                            In this case, the redirection (>) is quoted on the present shell and works correctly inside the called shell. The called_shell is used as the $0 parameter (the name) of the child shell (sh).



                            That works well if a suffix is added the name of the file, but not if you use a prefix. For a prefix to work you need both to remove the ./ that find prepend to filenames with ${1#./} and to use the -execdir option.



                            You may (or may not) want to use the -iname option so that files named *.JPG or *.JpG or other variations are also included.



                            find . ( -iname '*.jpg' -o -iname '*.jpeg' ) -execdir sh -c '
                            cjpeg -quality 80 "$1" > optimized_"${1#./}"
                            ' called_shell '{}' ;


                            And, you may (or may not) also want to call the shell once per directory instead of once per file by adding a loop (for f do … ; done) and a + at the end:



                            find . ( -iname '*.jpg' -o -iname '*.jpeg' ) -execdir sh -c '
                            for f; do cjpeg -quality 80 "$f" > optimized_"${f#./}"; done
                            ' called_shell '{}' +


                            And, finally, as cjpeg is able to directly write to a file, the redirection could be avoided as:



                            find . ( -iname '*.jpg' -o -iname '*.jpeg' ) -execdir sh -c '
                            for f; do cjpeg -quality 80 "$f" -outfile optimized_"${f#./}"; done
                            ' called_shell '{}' +






                            share|improve this answer














                            share|improve this answer



                            share|improve this answer








                            edited 2 days ago

























                            answered 2 days ago









                            Isaac

                            9,42911443




                            9,42911443






















                                up vote
                                3
                                down vote













                                cjpeg has an option that lets you write to a named file, rather than standard output. If your version of find supports the -execdir option, you can take advantage of that to make the redirection unnecessary.



                                find . ( -name '*.jpg' -o -name '*.jpeg' ) 
                                -execdir cjpeg -quality 80 -outfile optimized_'{}' '{}' ;


                                Note: this actually assumes the BSD version of find, which appears to strip the leading ./ from the file name when exanding to {}. (Or conversely, GNU find adds ./ to the name. There's no standard to say which behavior is "right".)






                                share|improve this answer























                                • If your find supports -execdir, you can use that instead of -exec. It causes the command to run in the directory where the file was found, and {} will become aa.jpg instead of ./t2/aa.jpg.
                                  – chepner
                                  2 days ago












                                • Still in error: cjpeg: can't open optimized_./aa.jpg.
                                  – Isaac
                                  2 days ago










                                • Hm, that appears to be a difference between GNU find and BSD find. (The perils of using non-standard extensions.)
                                  – chepner
                                  2 days ago












                                • A filename without a leading ./ seems to be more prone to errors. A reasonable solution is proposed in this answer.
                                  – Isaac
                                  2 days ago















                                up vote
                                3
                                down vote













                                cjpeg has an option that lets you write to a named file, rather than standard output. If your version of find supports the -execdir option, you can take advantage of that to make the redirection unnecessary.



                                find . ( -name '*.jpg' -o -name '*.jpeg' ) 
                                -execdir cjpeg -quality 80 -outfile optimized_'{}' '{}' ;


                                Note: this actually assumes the BSD version of find, which appears to strip the leading ./ from the file name when exanding to {}. (Or conversely, GNU find adds ./ to the name. There's no standard to say which behavior is "right".)






                                share|improve this answer























                                • If your find supports -execdir, you can use that instead of -exec. It causes the command to run in the directory where the file was found, and {} will become aa.jpg instead of ./t2/aa.jpg.
                                  – chepner
                                  2 days ago












                                • Still in error: cjpeg: can't open optimized_./aa.jpg.
                                  – Isaac
                                  2 days ago










                                • Hm, that appears to be a difference between GNU find and BSD find. (The perils of using non-standard extensions.)
                                  – chepner
                                  2 days ago












                                • A filename without a leading ./ seems to be more prone to errors. A reasonable solution is proposed in this answer.
                                  – Isaac
                                  2 days ago













                                up vote
                                3
                                down vote










                                up vote
                                3
                                down vote









                                cjpeg has an option that lets you write to a named file, rather than standard output. If your version of find supports the -execdir option, you can take advantage of that to make the redirection unnecessary.



                                find . ( -name '*.jpg' -o -name '*.jpeg' ) 
                                -execdir cjpeg -quality 80 -outfile optimized_'{}' '{}' ;


                                Note: this actually assumes the BSD version of find, which appears to strip the leading ./ from the file name when exanding to {}. (Or conversely, GNU find adds ./ to the name. There's no standard to say which behavior is "right".)






                                share|improve this answer














                                cjpeg has an option that lets you write to a named file, rather than standard output. If your version of find supports the -execdir option, you can take advantage of that to make the redirection unnecessary.



                                find . ( -name '*.jpg' -o -name '*.jpeg' ) 
                                -execdir cjpeg -quality 80 -outfile optimized_'{}' '{}' ;


                                Note: this actually assumes the BSD version of find, which appears to strip the leading ./ from the file name when exanding to {}. (Or conversely, GNU find adds ./ to the name. There's no standard to say which behavior is "right".)







                                share|improve this answer














                                share|improve this answer



                                share|improve this answer








                                edited 2 days ago

























                                answered 2 days ago









                                chepner

                                5,2901323




                                5,2901323












                                • If your find supports -execdir, you can use that instead of -exec. It causes the command to run in the directory where the file was found, and {} will become aa.jpg instead of ./t2/aa.jpg.
                                  – chepner
                                  2 days ago












                                • Still in error: cjpeg: can't open optimized_./aa.jpg.
                                  – Isaac
                                  2 days ago










                                • Hm, that appears to be a difference between GNU find and BSD find. (The perils of using non-standard extensions.)
                                  – chepner
                                  2 days ago












                                • A filename without a leading ./ seems to be more prone to errors. A reasonable solution is proposed in this answer.
                                  – Isaac
                                  2 days ago


















                                • If your find supports -execdir, you can use that instead of -exec. It causes the command to run in the directory where the file was found, and {} will become aa.jpg instead of ./t2/aa.jpg.
                                  – chepner
                                  2 days ago












                                • Still in error: cjpeg: can't open optimized_./aa.jpg.
                                  – Isaac
                                  2 days ago










                                • Hm, that appears to be a difference between GNU find and BSD find. (The perils of using non-standard extensions.)
                                  – chepner
                                  2 days ago












                                • A filename without a leading ./ seems to be more prone to errors. A reasonable solution is proposed in this answer.
                                  – Isaac
                                  2 days ago
















                                If your find supports -execdir, you can use that instead of -exec. It causes the command to run in the directory where the file was found, and {} will become aa.jpg instead of ./t2/aa.jpg.
                                – chepner
                                2 days ago






                                If your find supports -execdir, you can use that instead of -exec. It causes the command to run in the directory where the file was found, and {} will become aa.jpg instead of ./t2/aa.jpg.
                                – chepner
                                2 days ago














                                Still in error: cjpeg: can't open optimized_./aa.jpg.
                                – Isaac
                                2 days ago




                                Still in error: cjpeg: can't open optimized_./aa.jpg.
                                – Isaac
                                2 days ago












                                Hm, that appears to be a difference between GNU find and BSD find. (The perils of using non-standard extensions.)
                                – chepner
                                2 days ago






                                Hm, that appears to be a difference between GNU find and BSD find. (The perils of using non-standard extensions.)
                                – chepner
                                2 days ago














                                A filename without a leading ./ seems to be more prone to errors. A reasonable solution is proposed in this answer.
                                – Isaac
                                2 days ago




                                A filename without a leading ./ seems to be more prone to errors. A reasonable solution is proposed in this answer.
                                – Isaac
                                2 days ago










                                up vote
                                1
                                down vote













                                Create a script cjq80:



                                #!/bin/bash
                                cjpeg -quality 80 "$1" > "${1%/*}"/optimized_"${1##*/}"


                                Make it executable



                                chmod u+x cjq80


                                And use it in -exec:



                                find . ( -name '*.jpg' -o -name '*.jpeg' ) -exec cjq80 '{}' ;





                                share|improve this answer























                                • I had though about this, but it's not very handy. Especially as I had to incorporate this in a build process
                                  – Buzut
                                  2 days ago










                                • Just add the script to other build scripts, I find it more readable than doubly nested bash -c.
                                  – choroba
                                  2 days ago










                                • Well, it's a matter of taste. Now every option is specified so if someone encounters the same issue, he'll choose for himself :)
                                  – Buzut
                                  2 days ago










                                • @mosvy: Thanks, fixed.
                                  – choroba
                                  yesterday















                                up vote
                                1
                                down vote













                                Create a script cjq80:



                                #!/bin/bash
                                cjpeg -quality 80 "$1" > "${1%/*}"/optimized_"${1##*/}"


                                Make it executable



                                chmod u+x cjq80


                                And use it in -exec:



                                find . ( -name '*.jpg' -o -name '*.jpeg' ) -exec cjq80 '{}' ;





                                share|improve this answer























                                • I had though about this, but it's not very handy. Especially as I had to incorporate this in a build process
                                  – Buzut
                                  2 days ago










                                • Just add the script to other build scripts, I find it more readable than doubly nested bash -c.
                                  – choroba
                                  2 days ago










                                • Well, it's a matter of taste. Now every option is specified so if someone encounters the same issue, he'll choose for himself :)
                                  – Buzut
                                  2 days ago










                                • @mosvy: Thanks, fixed.
                                  – choroba
                                  yesterday













                                up vote
                                1
                                down vote










                                up vote
                                1
                                down vote









                                Create a script cjq80:



                                #!/bin/bash
                                cjpeg -quality 80 "$1" > "${1%/*}"/optimized_"${1##*/}"


                                Make it executable



                                chmod u+x cjq80


                                And use it in -exec:



                                find . ( -name '*.jpg' -o -name '*.jpeg' ) -exec cjq80 '{}' ;





                                share|improve this answer














                                Create a script cjq80:



                                #!/bin/bash
                                cjpeg -quality 80 "$1" > "${1%/*}"/optimized_"${1##*/}"


                                Make it executable



                                chmod u+x cjq80


                                And use it in -exec:



                                find . ( -name '*.jpg' -o -name '*.jpeg' ) -exec cjq80 '{}' ;






                                share|improve this answer














                                share|improve this answer



                                share|improve this answer








                                edited yesterday

























                                answered 2 days ago









                                choroba

                                25.5k44269




                                25.5k44269












                                • I had though about this, but it's not very handy. Especially as I had to incorporate this in a build process
                                  – Buzut
                                  2 days ago










                                • Just add the script to other build scripts, I find it more readable than doubly nested bash -c.
                                  – choroba
                                  2 days ago










                                • Well, it's a matter of taste. Now every option is specified so if someone encounters the same issue, he'll choose for himself :)
                                  – Buzut
                                  2 days ago










                                • @mosvy: Thanks, fixed.
                                  – choroba
                                  yesterday


















                                • I had though about this, but it's not very handy. Especially as I had to incorporate this in a build process
                                  – Buzut
                                  2 days ago










                                • Just add the script to other build scripts, I find it more readable than doubly nested bash -c.
                                  – choroba
                                  2 days ago










                                • Well, it's a matter of taste. Now every option is specified so if someone encounters the same issue, he'll choose for himself :)
                                  – Buzut
                                  2 days ago










                                • @mosvy: Thanks, fixed.
                                  – choroba
                                  yesterday
















                                I had though about this, but it's not very handy. Especially as I had to incorporate this in a build process
                                – Buzut
                                2 days ago




                                I had though about this, but it's not very handy. Especially as I had to incorporate this in a build process
                                – Buzut
                                2 days ago












                                Just add the script to other build scripts, I find it more readable than doubly nested bash -c.
                                – choroba
                                2 days ago




                                Just add the script to other build scripts, I find it more readable than doubly nested bash -c.
                                – choroba
                                2 days ago












                                Well, it's a matter of taste. Now every option is specified so if someone encounters the same issue, he'll choose for himself :)
                                – Buzut
                                2 days ago




                                Well, it's a matter of taste. Now every option is specified so if someone encounters the same issue, he'll choose for himself :)
                                – Buzut
                                2 days ago












                                @mosvy: Thanks, fixed.
                                – choroba
                                yesterday




                                @mosvy: Thanks, fixed.
                                – choroba
                                yesterday


















                                 

                                draft saved


                                draft discarded



















































                                 


                                draft saved


                                draft discarded














                                StackExchange.ready(
                                function () {
                                StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f481685%2ffind-exec-not-available-after%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

                                AnyDesk - Fatal Program Failure

                                How to calibrate 16:9 built-in touch-screen to a 4:3 resolution?

                                QoS: MAC-Priority for clients behind a repeater