Search code examples
bashfind

Exec on multiple files with `find`


I tried this line, but it doesn't work:

find . -name '*.tex' -exec 'perl -0777 -pi -e "s/\%\%if.+?\%\%fi//g" {}' \;

I get :

find: ‘perl -0777 -pi -e "s/\\%\\%if.+?\\%\\%fi//g" ./colophon.tex’: No such file or directory
find: ‘perl -0777 -pi -e "s/\\%\\%if.+?\\%\\%fi//g" ./glossary.tex’: No such file or directory

But the following works:

find . -name '*.tex' -print0 | xargs -n1 -0 perl -0777 -pi -e "s/\%\%if.+?\%\%fi//gs"

Is it possible to use -exec instead?


Solution

  • A command like

    find . -name '*.tex' -exec 'perl -0777 -pi -e "s/\%\%if.+?\%\%fi//g" {}' \;
    

    will cause the find program to receive these arguments (each on a separate line, without escaping):

    find
    .
    -name
    *.tex
    -exec
    perl -0777 -pi -e "s/\%\%if.+?\%\%fi//g" {}
    ;
    

    That is, the single quotes make the entire intended perl -0777 -pi -e "s/\%\%if.+?\%\%fi//g" {} command into a single command-line argument.

    However, find is not designed to work with that. It expects separate arguments instead:

    find
    .
    -name
    *.tex
    -exec
    perl
    -0777
    -pi
    -e
    s/\%\%if.+?\%\%fi//g
    {}
    ;
    

    When find parses its arguments and finds a -exec argument, it will treat everything from there until either ; or + as the command template. Within each token, {} will be replaced with a filename from the actual search process, and then these tokens represent the command that will be run.

    Thus, without quotes, the commands will look like perl -0777 -pi -e 's/\%\%if.+?\%\%fi//g' colophon.tex, (supposing that we re-constitute a command line that would tokenize the same way; of course, this is not necessary, since find already has the pre-processed tokens required to make a system call).

    With quotes, the commands will look like in the error message: the TeX filenames were interpolated into the command, but the command is still a single shell token which doesn't match the name of any program (hence, "No such file or directory"). It is the same as how explicitly typing 'perl -0777 -pi -e "s/\\%\\%if.+?\\%\\%fi//g" ./colophon.tex' (with the single quotes) at the command prompt wouldn't work.