Disclaimer: You are looking at a post I wrote some time ago. The information and opinions contained within may be outdated and may differ from my current views. Please proceed accordingly.

Edit Many Files With The Same Name

Apr 27, 2006 10:57 AM
Tags: bash, emacs, unix

There might be a way to do this with one less pipe, but it's close enough to an idiom that I'll document it for my own future reference:

emacs `find . -name "filename" `

(was emacs `find . -name "filename" | tr "\n" " " | sed -e 's/\.\///g'`)

  • find the filepaths
  • use tr replace newlines with spaces
  • strip the leading "./" with sed
  • use the backticks to treat the output (a space-delimited series of paths) as an argument to emacs

Non-geeks: trust me, this makes sense to somebody out there, and eventually someone will Google it and find this useful.

update I removed an unnecessary command. Also, watch out for filenames that contain whitespace (yuck). Thanks, Dossy and Edward.


Comments: Edit Many Files With The Same Name

Emacs shouldn't care if file paths start with "./" -- so that's unnecessary.

Also, the shell (if it's not braindead) shouldn't care about the newlines between file names.

Also: be careful of spaces embedded in filenames. It will cause Emacs some grief.

Posted by: Dossy Shiobara on April 27, 2006 12:38 PM | permalink

Why not do something like this?

find . -name "filename" | xargs emacs

Also, M-x find-grep-dired RET is your friend.

Posted by: Edward O'Connor on April 27, 2006 12:41 PM | permalink

I'm using bash 3.1.10 on FreeBSD 4.7.

Here's what happens:

.::[ root | /www/htdocs/[some folder] ]::.
$ find . -name "[some filename]" | xargs emacs
emacs: standard input is not a tty

In any case ...

Dossy: You are right about spaces in filenames.

Edward: I really need to look into that command. When I ran it, though, all it did was launch a buffer named *Find*, with some shell of sorts and output a bunch of filenames. I have no idea what to do next.

Posted by: Joe Grossberg on April 27, 2006 1:25 PM | permalink

If you want to be uber-paranoid about embedded quotes and spaces, this is where I'd go:

% emacs `find . -name FILENAME | while read i; do echo "\"$(echo $i | sed -e 's/\"/\\\"/g')\""; done`

It doesn't exactly roll off the tongue, but it's "correct" and complete.

Posted by: Dossy Shiobara on April 27, 2006 1:43 PM | permalink

Never mind, I'm smoking crack -- my tests didn't do what I expected because I forgot the magical "eval". Here's an example that *really* works:

$ eval vi `find . -name foo\* | while read i; do echo "\"$(echo $i | sed -e 's/\"/\\\"/g')\""; done`

To test, I did:

$ touch "foo\"bar"
$ touch "foo\'bar"
$ touch "foo bar"

And made sure vi opened all three correctly. The eval and the surrounding double quotes are what make the embedded spaces "work". The sed is only necessary to support filenames with double quotes embedded inside them.

This was all tested using:
GNU bash, version 2.05b.0(1)-release (i386-pc-linux-gnu)

Posted by: Dossy Shiobara on April 27, 2006 1:49 PM | permalink

Dossy:

I see how that replaces any '"' with a '\"' ... but where do the spaces get dealt with?

Posted by: Joe Grossberg on April 27, 2006 1:49 PM | permalink

By the way, the "find | xargs" idiom will launch N emacs processes, one for every line of input to xargs (which is the output from find, or one line per filename). It's not what you want.

Posted by: Dossy Shiobara on April 27, 2006 1:50 PM | permalink

Jeebus ... I'm glad "find | xargs" didn't work. :)

Posted by: Joe Grossberg on April 27, 2006 1:52 PM | permalink

"I see how that replaces any '"' with a '\"' ... but where do the spaces get dealt with?"

Joe, this portion:

[...] do echo "\" [...] \"" [...]

Basically, look at what command will be eval'ed, and I think the "why this works" will be clear to you:

$ echo vi `find . -name foo\* | while read i; do echo "\"$(echo $i | sed -e 's/\"/\\\"/g')\""; done`
vi "./foo'bar" "./foo\"bar" "./foo bar"

Posted by: Dossy Shiobara on April 27, 2006 1:52 PM | permalink

Sorry, slight misinformation: xargs will only launch one emacs per filename if you specify "xargs -n1 emacs" ... sorry.

Posted by: Dossy Shiobara on April 27, 2006 1:54 PM | permalink

I poked at this for a while and I'm not coming up with much more than the others did. At first -print0 and -0 options for find and xargs respectively sounded good but it runs into similar issues.

Posted by: Steven Klassen on April 28, 2006 6:11 PM | permalink

To open a bunch of files in an editor:

find . -name 'filename' -print0 | xargs -0 gvim

This takes care of quoting by using null-padded strings, removes the unnecessary backticks, and is much easier to read. If it makes you feel better, I found these switches after trying to build a solution much like to yours.

Posted by: kamaraga on April 28, 2006 6:14 PM | permalink

No more comments! Either someone has violated Godwin's Law, I'm tired of the discussion or, most likely, the ten-week window has closed. You can, however, contact me through email.