Search code examples
bashxargs

xargs with multiple commands


In the current directory, I'd like to print the filename and contents in it. I can print filenames or contents separately by

find . | grep "file_for_print" | xargs echo
find . | grep "file_for_print" | xargs cat

but what I want is printing them together like this:

file1
line1 inside file1
line2 inside file1
file2
line1 inside file2
line2 inside file2

I read xargs with multiple commands as argument and tried

find . | grep "file_for_print" | xargs -I % sh -c 'echo; cat;'

but doesn't work. I'm not familiar with xargs, so don't know what exactly "-I % sh -c" means. could anyone help me? thank you!


Solution

  • To start with, there is virtually no difference between:

    find . | grep "file_for_print" | xargs echo
    

    and

    find . -name "file_for_print*"
    

    except that the second one will not match filenames like this_is_not_the_file_for_print, and it will print the filenames one per line. It will also be a lot faster, because it doesn't need to generate and print the entire recursive directory structure just in order for grep to toss most of it away.

    find . -name "file_for_print*"
    

    is actually exactly the same as

    find . -name "file_for_print*" -print
    

    where the -print action prints each matched filename followed by a newline. If you don't provide find with any actions, it assumes you wanted -print. But it has more tricks up its sleeve than that. For example:

    find . -name "file_for_print*" -exec cat {} \;
    

    The -exec action causes find to execute the following command, up to the \;, replacing {} with each matching file name.

    find does not limit itself to a single action. You can tell it to do however many you want. So:

    find . -name "file_for_print*" -print -exec cat {} \;
    

    will probably do pretty well what you want.

    For lots more information on this very useful utility, type:

    man find
    

    or

    info find
    

    and read all about It.