1

I have a bunch of folders in a directory with files in them. Most of the filenames have region codes (retropie), and the scrubber will not match roms with single letter region codes (u,j,e,etc.). I need to remove all region codes. Region codes are all contained in parentheses "(...)". Is there anyway to remove all parentheses and the text between them?

For example:

Files are titled

~/RetroPie/roms/<system>/

And I want to rename roms like so:

Super Mario Bros (J).nes  
Super Random game (J,U,E).nes  

to

Super Mario Bros.nes  
Super Random game.nes

Hope That fixes the [on hold] tag thing.

mas
  • 1,909
  • 2
  • 18
  • 32
pcs3rd
  • 65
  • 3
    Examples of filenames and what they would be renamed as would be welcomed. Also, do you have access to the Perl rename utility? – Kusalananda Mar 05 '19 at 21:06
  • 3
    The Perl rename might exist on your system as /usr/bin/file-rename or /usr/bin/prename – glenn jackman Mar 05 '19 at 21:13
  • I might, i'm in school right now. Do I need to be more clear in op? – pcs3rd Mar 06 '19 at 16:31
  • Do you want “to remove all parenthesis and the text between them”, as you say?  If so, does the bit about “the scrubber will not match roms with single letter region codes (u, j, e, etc.)” really matter?  Should Q*bert (spring) be left alone because spring is more than one letter? And what about Abc (def) ghi (J,K)?  (Note: you said that you were going to respond to Kusalananda’s comment, but you didn’t.) – G-Man Says 'Reinstate Monica' Mar 06 '19 at 18:17

2 Answers2

3
find . -iname '*.nes' | xargs -I {} rename -n 's/ *\(.*\)//g' "{}"

Verify that output looks good then run it again without the -n to apply the changes.

user1133275
  • 5,574
  • Once I came to understand rename I came to adore it. Answers like this that use find-centric -exec's with mv are much less capable in my opinion. Of course, this could just be my inexperience with find -exec's. – mas Mar 05 '19 at 21:25
  • 1
    @malan The thing with Perl and this utility is that it's not necessarily available on all types of Unix systems by default, but find and mv are. – Kusalananda Mar 05 '19 at 21:35
  • @Kusalananda the OP said retropie which is debian based, and the other half of the market is fedora based, (there are Arch, bsd, solaris and the stragglers that don't make up 1% of the market), all of which have perl AFAIK... and if you are working on a system without such modern basics then it's time to upgrade your toolset or resign yourself to doing things from 1990s scratch. – user1133275 Mar 06 '19 at 01:54
  • Also note that some systems have this Perl-based tool available as prename rather than rename, and that there's at least one other common implementation of rename that is not implemented in Perl and that would not accept the arguments that you give it. – Kusalananda Mar 06 '19 at 06:08
  • 2
    In addition to that, your given command would, I believe, remove not only the parentheses and the text inside them, but also any text between two sets of parentheses. Use a non-greedy regular expression instead. – Kusalananda Mar 06 '19 at 06:12
  • Actually, @Kusalananda, I was kind of looking to remove any parenthesis and any characters between an opening and a closing. I will actually improve my question. Sorry for my somewhat generalized question. – pcs3rd Mar 06 '19 at 16:54
2

Using the Perl rename utility, if available,

find . -type f -name '* (*)*' -exec rename 's/ \([^)]*\)//g' {} +

This would find all regular files in or below the current directory that have at least one matched set of parentheses in their names. For batches of such files, rename is used to rename the files by removing the parentheses that we know are there, including the leading space before the left parenthesis.

If you don't have rename, then...

Assuming you'd want to remove all parentheses from all names of regular files in the current directory or below, the following find command would do that:

find . -type f -name '* (*)*' -exec bash -O extglob -c '
    for pathname do
        filename=${pathname##*/}
        mv -i "$pathname" "${pathname%/*}/${filename// (!(*\)*))}"
    done' bash {} +

This would locate all regular files whose filename has parentheses in it. For batches of these files, a short bash script would be called.

The bash script would iterate over the current batch of found pathnames and would, for each, first extract the filename portion of the pathname, and then rename the file by removing the parentheses and their content.

There are three parameter substitutions used in the code. They are

  1. ${pathname##*/}: This strips off the directory path from the pathname and leaves only the filename. It is, in this instance, the same as $(basename "$pathaname").

  2. ${pathname%/*}: This removes the filename from the pathname and leaves the directory path. This is, in this instance, the same as $(dirname "$pathname").

  3. ${filename// (!(*\)*))}": This is a bash-specific substitution that removes any space+parentheses from the value of $filename. The sub-pattern !(*\)*) is an extended globbing pattern that matches any string that does not contain a ). We use that in removing individual parentheses so that a filename such as 0 (1) 2 (3) is turned into 0 2 and not just 0.

If there are multiple parentheses, all of these would be removed (as illustrated above).

If you are certain that you don't have directories with parentheses like this, then you may use the shorter command

find . -type f -name '* (*)*' -exec bash -O extglob -c '
    for pathname do
        mv -i "$pathname" "${pathname// (!(*\)*))}"
    done' bash {} +

Testing the first command:

$ ls -l
total 0
-rw-r--r--  1 kk  wheel  0 Mar  6 18:21 Super Mario Bros (J).nes
-rw-r--r--  1 kk  wheel  0 Mar  6 18:21 Super Random game (J,U,E).nes
$ find . -type f -name '* (*)*' -exec prename 's/ \([^)]*\)//g' {} +
$ ls -l
total 0
-rw-r--r--  1 kk  wheel  0 Mar  6 18:21 Super Mario Bros.nes
-rw-r--r--  1 kk  wheel  0 Mar  6 18:21 Super Random game.nes

The other commands give the same results.

Kusalananda
  • 333,661
  • I'm curious why you were downvoted. No one commented. – mas Mar 06 '19 at 18:13
  • @malan No, people sometimes don't feel like commenting when they downvote, and there's no requirement to do so. However, it makes it difficult to correct any errors or misunderstandings. I don't worry about it too much. – Kusalananda Mar 06 '19 at 18:15
  • I was wondering about it, too. – G-Man Says 'Reinstate Monica' Mar 06 '19 at 18:16
  • 1
    @G-Man Thanks for the language edits (etc.) – Kusalananda Mar 06 '19 at 19:02
  • I'm curious about your rename syntax. @user1133275 uses the same syntax but it doesn't work with my utility. I kept getting errors until I went with rename '<orig>' '<replacement>' '<filename>'. I had to use quotes because I had spaces in the names. I had thought that was the problem, but it wasn't. I'm using rename from util-linux 2.33.1 in Arch. – mas Mar 09 '19 at 14:07
  • 1
    @malan There are two common implementations of rename. One works the way that I have shown here, and it's often referred to as "the Perl rename" (since it's a Perl script). It is sometimes also called prename. The other one, the one you are using, is less flexible, and I don't know very much about it. – Kusalananda Mar 09 '19 at 14:21