20

I have a GB's worth of music on my HDD that was formatted with EXT4. I want to move these files to a FAT formatted HDD partition. However, I can't move most of my files because they have ":" in the names (For example, "Act 2: ....." for operas). Is there a way with command line to rename all of my files from "XXXX:XXXX" to "XXXX-XXXX"?

5 Answers 5

34

If all your files are in a single directory, try:

rename 's|:|-|g' *

(where * can be changed to something more restrictive if you'd like)

If you have many files in a directory tree, try this from the base of the tree:

find . -name "*:*" -exec rename 's|:|-|g' {} \;

You can add the option -n right after rename to have it tell you what it WOULD do without ACTUALLY doing it. This might help you avoid accidentally stepping on other files or something else bad...

5
  • 2
    Single directory solution will work but nested solution won't if directories themselves have :s in their names. This is because in the output of find . the name of a subdirectory precedes its contents. So if you have a file /1:/2: first /1:/ will be renamed to /1-/. Now you cannot rename /1:/2: to /1-/2- because /1:/2: doesn't exist.
    – Prasanth S
    Dec 10, 2012 at 13:57
  • 2
    For directories: find . -type d -readable -writable -exec rename 's|:|-|g' {} \; And then files: find . -type f -readable -writable -exec rename 's|:|-|g' {} \;
    – user8290
    Dec 10, 2012 at 14:07
  • @Christopher The command for directories will fail if there are two levels of directories with : in their names. Eg: /1:/2:/ where 2: is also a directory. Of course, if this is not the case in Ryan's situation, then this will work.
    – Prasanth S
    Dec 10, 2012 at 15:13
  • For multiple levels of sub-dirs use: for i in {1..20}; do find . -maxdepth $i -mindepth $i -name "*:*" -exec rename 's|:|-|g' {} \;; done. Change 20 to the maximum depth of the dir. structure. Doesn't have to be exact - can be larger. Will take time if set to a very large number though.
    – Prasanth S
    Dec 12, 2012 at 14:18
  • 1
    sudo apt install rename
    – sarki_roka
    Dec 30, 2020 at 11:29
1

This is a solution in python which handles the case where the files are not necessarily in the same directory.

import os
torename = []
rootdir = "The main directory"
logfile = "Path to log file" #Eg: logfile = "/home/prasanth/renamelog"
for (path, dirs, files) in os.walk(rootdir):
    for dirname in dirs:
        if ':' in dirname:
            torename.append(os.path.join(path, dirname))
    for filename in files:
        if ':' in filename:
            torename.append(os.path.join(path, filename))

print "No of files/dirs to rename =", len(torename)
a = raw_input("Continue? (y/n) ")
if a == 'y':
    torename.reverse()
    for oldname in torename:
        directory, filename = os.path.split(oldname)
        newname = os.path.join(directory, filename.replace(':', '-'))
        command = 'mv %s %s > /dev/null' % (repr(oldname), repr(newname))
        os.system(command)
        f = open(logfile, 'a')
        f.write(oldname + '\n')
        f.close()
else:
    print "Aborted."
  1. Save this to a file (say) rename.py.
  2. Change rootdir to the outermost directory under consideration (Use complete path name starting with /. No shorthands or env variables like ~ allowed). No need to put \ before special characters - for example if the outermost dir is /.../My HDD, put rootdir = "/.../My HDD" NOT rootdir = "/.../My\ HDD" (Note the "s) [I'm being this explicit only because you may be unfamiliar with python. No disrespect intended.]
  3. Change logfile to desired location of logfile. In the end, this file will contain the list of files renamed - for future reference.
  4. Call python rename.py.

Warning: Do test on a small sample before risking an entire GB of music.

Details: Renaming is performed from the innermost files outward.

1

The top answer didn't work on my system. This one did.

To show a test run:

rename -nv ":" "_" *.webp

To run:

rename ":" "_" *.webp

1
  • 1
    I'm not sure why, but I was having issues using single quotes. When I tried your suggestion, with double quotes, it worked fine. Thanks a bunch! :)
    – Sawta
    Sep 18, 2022 at 4:54
0

Im not at my linux machine right now so I can only give rough information.

Linux has a commandline utility called rename which works with among other inputs, regular expressions or regexes. You should be able to use that along with a regex like "s/:/-/" on your files to achieve the rename you want.

Just to be safe, do it in small batches and/or first test with the simulation (rename has a flag which just gives you the oldname and new name of the file without actually renaming - use this to verify first)

0

I realize this is a very old post. AeroGT80's recursive solution is very thorough, but it is pretty slow. I had it running for about half an hour on a slower server and it only got about half done - I think it was about 73,000 files in about 300 sub-directories.

The solution below will operate much quicker (it operates on all files in a directory, instead of each file one-by-one - using AeroGT80's non-recursive solution). The only problem is, it only goes down one directory deep (so it's not fully recursive like his solution is), but I'm sure it could be modified easily enough.

#!/bin/bash
for D in *; do
        if [ -d "${D}" ]; then
                #echo "${D}"
                pushd "${D}" > /dev/null
                rename 's|:|-|g' *
                popd > /dev/null
        fi
done

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .