cat “arquivo de entrada é arquivo de saída” ao tentar combinar vários arquivos em um

4

O plano era coletar todas as linhas de origem do Java em um arquivo, de forma recursiva:

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

Mas houve um erro:

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

O arquivo all.java não existia antes desse comando, então pensei que talvez xargs estivesse tentando executar cat >> all.java file1 file2 file3 ...

    
por Evgeni Sergeev 19.01.2014 / 14:00

2 respostas

6

Primeiro de tudo, você pode ignorar com segurança esse erro. O comando será executado com sucesso e, corretamente, ignorará all.java . É simplesmente avisá-lo que isso aconteceu.

De qualquer forma, para evitar o erro, você pode usar a opção tee e find's exec:

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

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

Assim, você pode usar -exec para informar find para executar um comando em cada um dos seus resultados. O {} é substituído pelo nome do arquivo / diretório real encontrado. O + é apenas o marcador que diz find que o comando termina aqui. Eu o uso em vez de \; porque ele executará menos comandos, pois tentará combiná-los com o menor número de execuções possíveis.

Ou use ! do Google para excluir all.java :

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

Ou globbing :

$ shopt -s globstar
$ cat **/*.java > all.java
    
por 19.01.2014 / 18:51
3

O problema foi que primeiro o arquivo all.java foi criado, então find o encontrou e o alimentou para cat , o que não gostou porque estava produzindo lá.

Possível solução:

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

Ou:

$ find . -name '*.java' | xargs cat >> ../all.java
    
por 19.01.2014 / 14:00