5

I have folder which contains many .mkv files that I'd like to rename without having to manually do so.

The pattern is this:

...
[XVC]_Control_-_10_-_Doctors_[SCB055Y].mkv
[XVC]_Control_-_11_-_Engineers_[50OPZ00].mkv
...

I'd like the results to be:

...
Control-10-Doctors.mkv
Control-11-Engineers.mkv
...

I've tried using find and piping it through sed and tr, but I can't seem to get it to work.

This is what I've tried so far:

find . -iname "*.mkv" -exec sed -e 's/\[[^][]*\]//g' {} \;
find . -type f "*mkv" | sed 's/\[[^][]*\]//g' | tr -d '_'
find . "*.mkv" -type f -print0 | xargs -0 sed -i '' -e 's/\[[^][]*\]//g' | tr -d '_'
find . -iname "*.mkv" -exec rename 's/\[[^][]*\]//g' .mkv '{}' \;
find . -iname "*.mkv" -exec rename -n 's/\[[^][]*\]//g' {} ";"

And several others, but none seem to work. I find it puzzling that the command command below works:

(input)
echo '[XVC]_Control_-_10_-_Doctors_[SCB055Y].mkv' | sed 's/\[[^][]*\]//g' | tr -d '_'`

(output) Control-10-Doctors.mkv


EDIT:

$ file $(which rename)
/usr/bin/rename: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=d7b5a08ee8556c59dbdda26e998e20d4762c2bbc, for GNU/Linux 3.2.0, stripped
rename -n 's/\[.+?\]//g; s/_//g' *mkv
rename: not enough arguments
Try 'rename --help' for more information.
telometto
  • 1,975
  • 4
    Which Linux? Do you have perl rename? – terdon Aug 12 '22 at 18:31
  • @terdon I'm using Fedora 36. I'm sure I have perl and the rename command installed, if that's what you're thinking of. – telometto Aug 12 '22 at 18:39
  • 2
    No, I am wondering if the rename command you used is the one from util-linux or if it is the perl script often installed as rename on Debian-based systems. What does file $(which rename) return? Do you have either prename or perl-rename installed? See What's with all the renames: prename, rename, file-rename? – terdon Aug 12 '22 at 18:47
  • 1
    Sometimes an installation is convoluted and file $(which rename) will only show a link, and you have to follow that link to find what kind of program it points to (sometimes in several steps). For this reason I made the shellscript what-about, that does that job for us. See this link. – sudodus Aug 12 '22 at 19:26
  • @sudodus thanks for the script. I don't use a Debian-based distro, though (Fedora), so I don't have dpkg installed; is there an alternative I can use to substitute the command inside the script? – telometto Aug 12 '22 at 19:44
  • @sudodus I tried re-running the script and I get the following errors: what-about: line 73: file: command not found; dpkg-query: no path found matching pattern /usr/bin/rename; dpkg-query: no path found matching pattern *rename*. – telometto Aug 12 '22 at 19:51
  • This link may help you (to use dnf) – sudodus Aug 12 '22 at 19:53
  • I see from your edited [original] question, that it is not perl rename, but a compiled program. You should read its manual, man rename in order to check which options and commands that are relevant. They might be [slightly?] different from what should be used in perl rename. – sudodus Aug 12 '22 at 20:11
  • If you have util-linux rename, the syntax is very different from perl rename. At the end of man rename you might find information telling which version of rename it is. Or run rename -V – sudodus Aug 12 '22 at 20:22

1 Answers1

6

This will work with perl-rename (called rename or prename or perl-rename depending on your distribution):

$ rename -n 's/\[.*?\]|_//gs' ./*.mkv
[XVC]_Control_-_10_-_Doctors_[SCB055Y].mkv -> Control-10-Doctors.mkv
[XVC]_Control_-_11_-_Engineers_[50OPZ00].mkv -> Control-11-Engineers.mkv

If that gives you the output you want, run it again without the -n to actually rename the files.

Alternatively, write a little loop:

find . -iname "*.mkv" -print0 |
    while IFS= read -rd '' file; do
        newName=$(printf -- '%s\n' "$file" | perl -pe 's/\[.*?\]|_//gs')
        echo mv -- "$file" "$newName"
    done

If that looks right, remove the echo and run it again to actually rename the files.


Your commands didn't work for various reasons.

  1. find . -iname "*.mkv" -exec sed -e 's/\[[^][]*\]//g' {} \;

    This one is running the sed command on the file itself, so it would only make changes to the file's contents, not the name. And not even that since you aren't using -i which means that it just prints the changed contents to standard output.

  2. find . -type f "*mkv" | sed 's/\[[^][]*\]//g' | tr -d '_'

    Here, the find is printing file names but those are just passed as text (a stream) to sed which modfies its input, but doesn't alter the file name. It's the same as echo foo | sed 's/f/b/'. That won't rename a file named foo if one happens to be there.

  3. find . "*.mkv" -type f -print0 | xargs -0 sed -i '' -e 's/\[[^][]*\]//g' | tr -d '_'

    Here, the sed is being run on the files again, so it is basically the same as above except that it would actually modify the file if any of its contents match. As these are binary files, it is unlikely but not impossible that you have actually modified them.

  4. find . -iname "*.mkv" -exec rename 's/\[[^][]*\]//g' .mkv '{}' \;

    This one is actually capable of renaming the files, but since you are passing the string .mkv as the first argument to the rename command, it is trying to rename a file called .mkv. As you presumably have no such file, it does nothing. The second argument, '{}', is ignored. This would have worked:

    find . -iname "*.mkv" -exec rename 's/\[[^][]*\]//g' {} \;
    

    But it would have renamed the files to _Control_-_10_-_Doctors_.mkv and _Control_-_11_-_Engineers_.mkv since you weren't handling the _ in that one.

  5. find . -iname "*.mkv" -exec rename -n 's/\[[^][]*\]//g' {} ";"

    This one should have worked! It would just not have done the correct renaming, just as described in 4 above.

terdon
  • 242,166
  • Thank you for the thorough explanation, very interesting read. I encountered an error, though. Please see my updated answer. – telometto Aug 12 '22 at 18:56
  • 1
    @telometto you're welcome, but that isn't an error. It's as I said in the comments of your question: that's the rename executable from the util Linux package, you need to find perl-rename instead. I assumed that's what you were using because you were using its syntax. See the link I gave you and look for the right name in the red hat repositories. It's probably perl-rename. – terdon Aug 12 '22 at 21:37
  • I installed prename, executed the command you gave me, and it worked a charm! Again, many, many thanks! – telometto Aug 13 '22 at 05:19
  • @gilles the command is called perl-rename on many systems. It isn't "Perl's rename", as in the rename of perl, it's a rename script, written in perl. – terdon Dec 22 '22 at 23:22
  • Perl's rename script if you prefer :) – Gilles Quénot Dec 22 '22 at 23:25
  • I prefer to use the actual name, really. It's perl-rename on my Arch and I think also on red hat derived systems. And I'm not sure if it's the one that ships with perl. There are at least three different ones: https://unix.stackexchange.com/q/229230/22222 – terdon Dec 22 '22 at 23:34
  • What is important, is to 'discard' the one from util-linux like Debian drops, that looks few used around. Perl's family of rename commands are all very close enough for basic usage. AFAIK all implements -n – Gilles Quénot Dec 23 '22 at 07:42