views:

213

answers:

4

I have a directory like this:

dir
dir/somefile.txt
dir/subdir/subsub/somefile2.txt
dir/subdir2/somefile.txt

and I want to open all the files in all the subdirectories in a single instance of a command. I was trying find with -exec, or xargs, but these open each file with a separate instance of a command.

Basically, I want something that ends up like kate dir/somefile.txt dir/subdir/subsub/somefile2.txt dir/subdir2/somefile.txt, but for any number of files in any number of subdirectories. I'm using bash, but any script suggestions are fine.

clarification: I didn't just mean .txt files, but any ascii file (ie. .php, .txt, .html, etc..)

+2  A: 

kate $(find dir -type f)

system PAUSE
probable should be `kate $(find dir -type f)` unless you want kate to edit directories.
Rudedog
Also, it will open *all* files with Kate, possibly opening files which contain binary data, e.g. PDFs.
Grundlefleck
so will -type f, won't it Grundlefleck?
naught101
@Grundle, OP said "I want to open all the files in all the subdirectories", not just .txt files.
system PAUSE
@naught, `-type f` just means "files, not directories", while `-name *.txt` means "all the .txt files" ... So depending on what you want, you might choose to use either or both of those params. Your original question said "all the files in all the subdirectories".
system PAUSE
It's using `-type f` alone that could present problems. A (not bulletproof) measure would be to only open files that end with a .txt extension, as per other answers (not just my own).
Grundlefleck
@system PAUSE, good point. Will ask OP to clarify.
Grundlefleck
yeah, I actually meant all ascii files (editing drupal modules, with .info, .module, .install, .inc files), but since I know there's no binary files in the directory, `-type f` is sufficient
naught101
Okeydoke. -1 removed.
Grundlefleck
+3  A: 

There are several possible options for this. These answers are based on your scenario where you know all files can be opened by kate, and you want to open files with any extension.

find dir -type f -exec kate {} +


kate $(find dir -type f)


kate `find dir -type f`

The second and third forms are almost equivalent. The main difference[1] is that the first version will handle files with whitespace in their name, while the second and third do not.

[1] Thanks for pointing this out NVRAM, I didn't realise when I first posted the answer.

Grundlefleck
your first one, using the find command will "open" kate for each .txt. 2nd and 3rd choices are better...
NVRAM
@levislevis85 - ending `find` with ';' gave that behaviour, I found when I ended it with '+' all files were opened within one instance of kate.
Grundlefleck
+1 as the '+' is a neat trick, new to me.
system PAUSE
+3  A: 

Try

kate `find . -name \*.txt -type f`

where the -type f prevents you from hitting directories.

Here is an example using ls -1 instead of kate:

edd@ron:~/src/debian/R$ ls -1 `find . -type f -name \*.txt`
./R-2.10.0/src/extra/graphapp/readme.txt
./R-2.10.0/src/extra/xdr/copyrght.txt
./R-2.10.0/src/extra/xdr/README.txt
./R-2.10.0/src/gnuwin32/fixed/etc/rgb.txt
./R-2.10.0/src/gnuwin32/installer/CustomMsg.txt
./R-2.10.0/src/library/grid/inst/doc/changes.txt
./R-2.10.0/src/unix/system.txt
./R-2.9.2-ra-1.2.8/src/extra/graphapp/readme.txt
./R-2.9.2-ra-1.2.8/src/extra/xdr/copyrght.txt
./R-2.9.2-ra-1.2.8/src/extra/xdr/README.txt
./R-2.9.2-ra-1.2.8/src/gnuwin32/fixed/etc/rgb.txt
./R-2.9.2-ra-1.2.8/src/gnuwin32/installer/CustomMsg.txt
./R-2.9.2-ra-1.2.8/src/library/grid/inst/doc/changes.txt
./R-2.9.2-ra-1.2.8/src/unix/system.txt
edd@ron:~/src/debian/R$

and if you really want all files in subdirectories the call simplifies to

kate `find . -type f`

if you are in dir/ or else

kate `find dir -type f`
Dirk Eddelbuettel
+1 Since I came up with the same solution (deleted my answer since i was late).
ChristopheD
Backquotes! Nice!
naught101
Backquotes are the same as `$( )` in modern bash, and `$( )`'s are easier to nest, if you ever need to.
system PAUSE
This doesn't handle files with spaces in their names. Since `kate` doesn't require standard input, it's better to run **find . -name '*.txt' -type f -print0|xargs -0 -r kate**
NVRAM
Agreed, but backquotes are a little more _portable_ than `$()`, and my fingers have gotten more used to them over the years.
Dirk Eddelbuettel
A: 

You're either not very familiar with xargs, or you're not using it correctly, because what you're trying to do is exactly the problem xargs is designed to solve: Given an arbitrarily long list of strings, pass them as arguments to a program in as few executions as possible while not exceeding the system limits on the number of arguments a program can take.

You're right for find ... -exec, but that can also be fixed. Just add + at the end of the find command and voila, it behaves like xargs.

None of the solutions above that use kate $(...) (or the equivalent with backticks) work in general (they don't support file names with spaces, will not run at all if the list of files is very long). Both find ... + and xargs get around these limitations.

Idelic
Actually the `find` with **+** is *better* than `xargs` since the launched program may use standard input (probably the terminal). Running `find ... | xargs vi` will fail, but `find ... -exec vi '{}' +` should work.
NVRAM
Processes launched by `xargs` can also use standard input. What you probably meant is that their standard input is not a pseudo-terminal, and you're right. For that particular (and extremely uncommon) case, `find +` is what you want. For all other cases, `xargs` is *much* better because of its flexibility (for example, you can specify the max. number of arguments or characters in each command line).
Idelic
I was actually thinking of descriptor gymnastics to make processes launched by `xargs` read stdin, but I actually can't make it work. So, erase the first two sentences from my previous comment and the rest still applies.
Idelic
Sorry, I don't buy that it's *extremely uncommon* -- `vi` is just one use, `rm -i` is another. And yes, a script could recover the invoking program's stdin with "descriptor gymnastics" but the program launched by *xargs* will have the same stdin as *xargs* itself. Ultimately, both `find ... +` and `find | xargs` are extremely useful tools/patterns but with slightly different strengths. For my part, I should replace *"better"* in my first comment with *"often better"*
NVRAM
In my experience it *is* extremely uncommon to use xargs with an interactive program. You don't really want to run `rm -i` on 6000 files, do you? For a small number of files both commands are superfluous.
Idelic
Xargs doesn't play well with programs that need stdin for another purpose (interactive or not) so yes, it is uncommon to use it. I use `find|xargs` often, apparently when you'd call it superfluous, hence the frequency of wanting stdin is relative. **Caveat lector**.
NVRAM