19

I have something like this:

v_1/file.txt
v_2/file.txt
v_3/file.txt
...

and I want to rename those files to something like this:

v_1.txt
v_2.txt
v_3.txt
...

in the same directory.

I guess I can use rename but I can't figure out how to use it with folder and file renaming at the same time.

Jahid
  • 21,542
  • 10
  • 90
  • 108
giskou
  • 804
  • 2
  • 8
  • 22
  • Stack Overflow is not a code writing service. Please show your code. Since Stack Overflow hides the Close reason from you: *Questions seeking debugging help ("why isn't this code working?") must include the desired behavior, a specific problem or error and the shortest code necessary to reproduce it in the question itself. Questions without a clear problem statement are not useful to other readers. See: [How to create a Minimal, Complete, and Verifiable example](http://stackoverflow.com/help/).* – jww Mar 28 '18 at 17:55

3 Answers3

36

The result can be achieved with a bash for loop and mv:

for subdir in *; do mv $subdir/file.txt $subdir.txt; done;

Note that the solution above will not work if the directory name contains spaces. Related link.

Another solution based on comments (that works for directories having spaces in the name as well):

find . -type d -not -empty -exec echo mv \{\}/file.txt \{\}.txt \;
Community
  • 1
  • 1
Csq
  • 5,775
  • 6
  • 26
  • 39
  • 1
    `$subdir` should be `"$subdir"` and to remove the empty folders `find . -type d -empty -exec rm -rf \{\} \;` – giskou Jan 13 '13 at 18:04
  • @giskou If you like typing. A single `s#/file##` rename is a lot easier to type, and is at the right abstraction level. Repeating the same shell loop all your life to rename files gets old fast. – tchrist Jan 13 '13 at 18:06
  • 1
    @giskou: I don't see why empty folders are problem because the `mv` will simply fail. Also, removing an empty dir with `rm -rf` is overkill, you can simply use `rmdir`, it is safer. – Csq Jan 13 '13 at 18:23
  • @giskou: having that find command above it can also be modified to do the task: `find . -type d -not -empty -exec echo mv \"\{\}/file.txt\" \"\{\}.txt\" \;` – Csq Jan 13 '13 at 18:28
  • It doesn't work for me: `$ find . -type d -not -empty -exec echo mv \{\}/*.m4a \{\}.m4a \;` –  Jul 01 '16 at 07:24
  • Note that with the `echo` in it it won't actually *do* anything directly, plus it also tries to act in the current directory not just the subdirectories. This is what it looks like with both of these fixed: `find ./* -type d -not -empty -exec mv \{\}/file.txt \{\}.txt \;` – MalcolmOcean Jan 06 '20 at 06:35
  • suggest edit queue seems full, but yes to make it work, it should be `for subdir in *; do mv $subdir/file.txt "$subdir".txt; done;` – aechchiki Jun 09 '20 at 13:39
2

You can use rnm. The command would be:

rnm -fo -dp -1 -ns '/pd0/.txt' -ss '\.txt$' /path/to/the/directory

-fo implies file only mode.

-dp directory depth. -1 makes it recursive to all subdirectories.

-ns implies name string i.e the new name of the file.

/pd0/ is the immediate parent directory of the file which is subject to rename operation.

-ss is a search string (regex). '\.txt$' regex searches for file with .txt at the end of the filename.

/path/to/the/directory this is the path where the v_1, v_2 ... directories reside. You can pass the directories ( v_1, v_2 ...) too in place of the parent directory path. For example:

#from inside the parent directory
rnm -fo -dp -1  -ns '/pd0/.txt' -ss '\.txt$' v_* 
Jahid
  • 21,542
  • 10
  • 90
  • 108
0

Seem pretty straightforward to me:

$ mkdir /tmp/sandbox
$ cd /tmp/sandbox

$ mkdir v_{1,2,3}
$ touch v_{1,2,3}/file.txt

$ rename -v 's#/file##' v_{1,2,3}/file.txt
rename v_1/file.txt v_1.txt
rename v_2/file.txt v_2.txt
rename v_3/file.txt v_3.txt

$ ls -F
v_1/  v_1.txt    v_2/  v_2.txt    v_3/  v_3.txt
tchrist
  • 78,834
  • 30
  • 123
  • 180
  • 2
    the subfolders are about 130 and not just 3 :P – giskou Jan 13 '13 at 17:54
  • @giskou I do not understand why that matters: I was merely demonstrating that the technique works. The number of subdirs is immaterial, unless you hit `xargs` limits, and even that is trivial since the Perl `rename` will read filenames on stdin. – tchrist Jan 13 '13 at 18:01
  • I'm more to bash than perl and regexps. If you could explain your technique in detail... I really don't know what it does :P – giskou Jan 13 '13 at 18:20
  • @gisou You simply apply a standard search&replace command like you would use in any editor, so `s/foo/bar/g` changes all instances of `foo` in the filenames into instances of `bar`, etc. – tchrist Jan 13 '13 at 19:22