Take the 2-minute tour ×
Super User is a question and answer site for computer enthusiasts and power users. It's 100% free, no registration required.

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 ...

share|improve this question
    
Sounds like more of a unix.stackexchange.com question –  user66001 Jan 19 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 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 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 at 8:04

2 Answers 2

up vote 2 down vote accepted

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
share|improve this answer
    
Googling for cat {} + is a bit tricky... and stackoverflow.com/questions/2188199/… doesn't explain it... I don't think I've seen this pattern before. –  Evgeni Sergeev Jan 21 at 10:18
    
@EvgeniSergeev they are options to find. See update. –  terdon Jan 21 at 16:04

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

Or:

$ find . -name '*.java' | xargs cat >> ../all.java
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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