The plan was to collect all source lines of Java into one file, recursively:

$ find . -name '*.java' | xargs cat >> all.java

But there was an error:

cat: ./all.java: input file is output file

The file all.java didn't exist before this command, so I thought that maybe xargs was trying to run cat >> all.java file1 file2 file3 ...

  • Sounds like more of a unix.stackexchange.com question – user66001 Jan 19 '14 at 18:02
  • @user66001 It doesn't fit here? I've just tried and couldn't find a summary of this site's scope, other than it's for computer enthusiasts and power users... – Evgeni Sergeev Jan 21 '14 at 10:11
  • @user66001 this question is 100% on topic here. It would also be welcome at Unix & Linux but it is also a good fit for Super User. – terdon Jan 22 '14 at 14:34
  • @terdon & Evgeni Sergeev - Just thought seeing as their is a specific sub site for Linux/Unix related questions, that this question would be better residing there. Understand that it is technically on topic in both sites. Evgeni Sergeev - There is a site scope here which will also earn one a badge for reading top to bottom. – user66001 Jan 23 '14 at 8:04

First of all, you can safely ignore that error. The command will run successfully and it will, correctly, ignore all.java itself. It is simply letting you know that it did so.

Anyway, to avoid the error you could use tee and find's exec option:

$ find . -name '*.java' -exec cat {} + | tee all.java

From man find:

   -exec command ;
          Execute  command;  true  if 0 status is returned.  All following
          arguments to find are taken to be arguments to the command until
          an  argument  consisting of `;' is encountered.  The string `{}'
          is replaced by the current file name being processed  everywhere
          it occurs in the arguments to the command, not just in arguments
          where it is alone, as in some versions of find. 

   -exec command {} +
          This  variant  of the -exec action runs the specified command on
          the selected files, but the command line is built  by  appending
          each  selected file name at the end; the total number of invoca‐
          tions of the command will  be  much  less  than  the  number  of
          matched  files. 

So, you can use -exec to tell find to run a command on each of its results. The {} is replaced with the actual file/directory name found. The + is just the marker that tells find that the command ends here. I use it instead of \; because it will run fewer commands since it will attempt to combine them into as few runs as possible.

Or use find's ! to exclude all.java:

$ find . -name '*.java' ! -name all.java -exec cat {} +  >> all.java

Or globbing:

$ shopt -s globstar
$ cat **/*.java > all.java

The problem was that first the file all.java was created, then find found it and fed it to cat, which didn't like it because it was outputting there.

Possible solution:

$ find . -name '*.java' | xargs cat >> all.j


$ find . -name '*.java' | xargs cat >> ../all.java

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.