I have a bunch of directory, sub-directory, and filenames that were created in Linux with the following pattern: YYYY - MM - DD T HH : MM : SS (I added spaces for clarity but no spaces are in the directory/sub/file names; YYYY, MM, DD... are integers and '-', 'T', ':' are constants of the expression).

These directories/files were copied to Windows and then back to Linux, and the ':' got corrupted. Each place where there should be ':' there is '\357\200\242' which shows up as ??? when I do ls.

I know that fixing this should not be too complicated using a combination of mv and sed, but I'm very rusty on my piping, regex, and sed usage.

So far I have this

for a in *T*???*???*; do mv "$(echo "$a" | sed [***])"; done

The [***] should be a regex that changes *T*???*???* to *T*:*:* where the middle two * are each two digits. And this should rename both files and directories, recursively. I also suspect that ??? is not the correct input pattern to use here.

Alternate approach

I've seen a bunch of posts offering a combination of find and rename, but again, I am a bit rusty on the use of regex, and could not arrive at a good solution for this situation.

  • 2
    Have a look here for regex, to test it, here for sed , and come back with some updated work. – jayooin Jan 24 '19 at 14:52
  • @jayooin, thanks for the regex tool. It came in really handy. Once I figure out how to put it all together with Ralf's answer I will put something up. – AOK Jan 27 '19 at 13:08

Assuming \357\200\242 are octal numbers. Try:

rename -n 's/\o{357}\o{200}\o{242}/:/g' 2018-*

The command rename works with a Perl regular expression replace. Here it replaces three characters given as octal byte values with a colon.

Because of -n this just prints what it would do. So you are able to test without destroying something.

When you are sure that this does what you want, execute without -n.

If you need to traverse a entire directory tree, combine it with find:

find . -depth -exec rename -n 's/\o{357}\o{200}\o{242}/:/g' {} \;

Don't worry if the directory tree contains files that don't need to be renamed. If the regex replace does doesn't change the file name, the file is not renamed.

  • The regex seems to match the pattern correctly, but it is not looking inside sub-directories. However, I think I can take it from here and make it work. – AOK Jan 27 '19 at 7:46
  • @AOK See update – Ralf Jan 27 '19 at 17:17
  • This worked perfectly. If I understand correctly, find . tells it to find everything, then -depth tell the command to go into sub-directories, and -exec tells it to execute the above rename for each thing found. Would it be faster to add the regex also to the find, instead of a .? – AOK Jan 28 '19 at 11:05
  • One other question: If the rename changes a folder name, does that affect the iteration through the folder/file list contained within the changed folder name? Thanks! – AOK Jan 28 '19 at 11:16
  • 1
    The dot . says: Start searching from the current directory. It is recursive by default. The -depth means process directory content before directory itself. This would be useful if also a directory name needed rename. If you want to restrict to certain file names, you would add something like -name "2019-*" (after -depth). The find command is very powerful and complex. – Ralf Jan 28 '19 at 11:16

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.