3

Had to recover my music library from a HDD which died.... got everything I wanted but all music track names have _000 added at the end.

I really don't fancy going through 8000 individual music tracks and choosing to rename in order to remove the _000 string

How can I search the entire Music folder containing all the album sub-directories and remove every instance of _000 on all the individual track names?

3 Answers 3

2

Although mikesrv solution is much better and safer I think this can be done also with rename:

find Music/ -type f -name '*_000' -print0 | xargs -r0 rename -v '_000' ''

But there are still potential problems as mentioned, for example album_00020_000 will be renamed to album20 which obviously is not the desired behaviour.
I think on debian distribution was a perl tool rename which could do it. But unfortunately I can not find a way how to install it. So I found following perl script here which can suffice:

#!/usr/bin/perl -w
# rename - Larry's filename fixer
$op = shift or die "Usage: rename expr [files]\n";
chomp(@ARGV = <STDIN>) unless @ARGV;
for (@ARGV) {
    $was = $_;
    eval $op;
    die $@ if $@;
    rename($was,$_) unless $was eq $_;
}

So you can make this script executable and run:

find Music/ -type f -name '*_000' | /path_to_script/rename.pl 's/_000$//'
0
2
cd Music/..    &&
mkdir Music2   &&
pax -'rwls|\([^/]\)_000$|\1|p' Music Music2

If run from Music's parent directory, the above commands will create a directory called Music2 then mirror Music's path structure in Music2 w/ hardlinks while removing any occurrence of _000 found at the tail of any filename therein.

Afterward you'll have basically two routes to Music's contents in Music/.. - one in which some files are named with trailing _000 strings, and one in which there is one fewer _000 at the tail of each filename than there is in the other (except for files named only _000 which are not altered) - but the actual files are untouched. If you find that Music2/Music suits you better - rm -rf Music and mv Music2/Music Music afterward.

The assumption is that all of Music's contents are located on the same mounted filesystem and that it supports hardlinks.

The perl-rename used below is the one which can be found on cpan.org at ~pederst/rename. I installed it on an Arch Linux system with pacman. Now, I'm told there is another, safer perl-script by the same name which can also be found at cpan.org/~rmbarker/File-Rename-0.20. but I experienced no success with making that one work at all. This failure is more likely to do with my being perl-inept than anything else though.

Anyway, here's a little case study on the dangers of scripted rename solutions versus hardlinking based on a pattern.

mkdir Music Music2
echo file1 >Music/file
echo file2 >Music/file_000
pax -'rwls|_000$||p' Music Music2

I use the print flag for the -substitute option for pax above so pax prints only the names of the files it changes - though it links all of them. It prints:

Music/file_000 >> Music/file

Now let's see how we did:

grep . /dev/null Music/* Music2/Music/*

OUTPUT

Music/file:file1
Music/file_000:file2
Music2/Music/file:file2

Uhoh. The result of linking file from file_000 overwrote the dentry for a previously existent file when running the mirror op. But in this case the original link still exists - and so the file does as well. Besides retaining a copy dentry copy in the file's existing directory, pax (by default) -preserves all file attributes that it can regardless for those files which it must create or copy, as it must create directories (which cannot be hardlinked) and if the source is on a different file system (which can be avoided entirely with -X) it must copy.

And so the two different directories can be compared after the fact for differences before any unalterable changes are made. And with the print flag you can take the results it hands you and just cross-reference those to any existing originals - if they exist, you're at least a file shy in your new target.

On the other hand, though:

find Music -name \*_000 -exec perl-rename 's/_000$//' {} +
grep . /dev/null Music/*

OUTPUT

Music/file:file2

The same is not true when the last filesystem link for a file is overwritten - that file is history.

1

Use the find command to enumerate files in a directory and its subdirectories recursively. There are several ways to rename files. You can use the Linux rename command:

find Music -depth -name '*_000' -exec rename _000 '' {} \;

This removes the first occurrence of _000 in each file name. Beware that if you had files whose name contains _000 in the middle, this won't give you the desired name.

On Debian and derivatives (Ubuntu, Mint, …), the rename command is a different one; the Linux one is called rename.ul, and the renameone can be used this way (which always removes the _000 at the end even if there's one in the middle):

find Music -depth -name '*_000' -exec rename 's/_000$//' {} +

An easier way to rename these files is to install zsh (available in most distributions) and use its zmv function. Run autoload -U zmv (or put it in ~/.zshrc) then

zmv 'Music/**/*_000' '${f%_000}'

You must log in to answer this question.

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