I can do this:
$ find .
.
./b
./b/foo
./c
./c/foo
And this:
$ find . -type f -exec cat {} \;
This is in b.
This is in c.
But not this:
$ find . -type f -exec cat > out.txt {} \;
Why not?
I can do this:
$ find .
.
./b
./b/foo
./c
./c/foo
And this:
$ find . -type f -exec cat {} \;
This is in b.
This is in c.
But not this:
$ find . -type f -exec cat > out.txt {} \;
Why not?
find's -exec argument runs the command you specify once for each file it finds. Try:
$ find . -type f -exec cat {} \; > out.txt
or:
$ find . -type f | xargs cat > out.txt
xargs converts its standard input into command-line arguments for the command you specify. If you're worried about embedded spaces in filenames, try:
$ find . -type f -print0 | xargs -0 cat > out.txt
How about just redirecting the output of find into a file, since all you're wanting to do is cat all the files into one large file:
find . -type f -exec cat {} \; > /tmp/out.txt
Or just leave out the find which is useless if you use the really great Z shell (zsh
), and you can do this:
setopt extendedglob
(this should be in your .zshrc
)
Then:
cat **/*(.) > outfile
just works :-)
Maybe you've inferred from the other responses that the >
symbol is interpreted by the shell before find gets it as an argument. But to answer your "why not" lets look at your command, which is:
$ find . -type f -exec cat > out.txt {} \;
So you're giving find
these arguments: "." "-type" "f" "-exec" "cat"
you're giving the redirect these arguments: "out.txt" "{}"
and ";"
. This confuses find
by not terminating the -exec
arguments with a semi-colon and by not using the file name as an argument ("{}"), it possibly confuses the redirection too.
Looking at the other suggestions you should really avoid creating the output in the same directory you're finding in. But they'd work with that in mind. And the -print0 | xargs -0
combination is greatly useful. What you wanted to type was probably more like:
$ find . -type f -exec cat \{} \; > /tmp/out.txt
Now if you really only have one level of sub directories and only normal files, you can do something silly and simple like this:
cat `ls -p|sed 's/\/$/\/*/'` > /tmp/out.txt
Which gets ls
to list all your files and directories appending '/'
to the directories, while sed
will append a '*'
to the directories. The shell will then interpret this list and expand the globs. Assuming that doesn't result in too many files for the shell to handle, these will all be passed as arguments to cat, and the output will be written to out.txt.
In bash you could do
cat $(find . -type f) > out.txt
with $( ) you can get the output from a command and pass it to another