Engineer81
Engineer81

Reputation: 1014

How do I rename lots of files changing the same filename element for each in Linux?

I'm trying to rename a load of files (I count over 200) that either have the company name in the filename, or in the text contents. I basically need to change any references to "company" to "newcompany", maintaining capitalisation where applicable (ie "Company becomes Newcompany", "company" becomes "newcompany"). I need to do this recursively.

Because the name could occur pretty much anywhere I've not been able to find example code anywhere that meets my requirements. It could be any of these examples, or more:

company.jpg
company.php
company.Class.php
company.Company.php
companysomething.jpg

Hopefully you get the idea. I not only need to do this with filenames, but also the contents of text files, such as HTML and PHP scripts. I'm presuming this would be a second command, but I'm not entirely sure what.

I've searched the codebase and found nearly 2000 mentions of the company name in nearly 300 files, so I don't fancy doing it manually.

Please help! :)

Upvotes: 0

Views: 1749

Answers (4)

sorpigal
sorpigal

Reputation: 26086

There are few right ways to recursively process files. Here's one:

while IFS= read -d $'\0' -r file ; do
    newfile="${file//Company/Newcompany}"
    newfile="${newfile//company/newcompany}"
    mv -f "$file" "$newfile"
done < <(find /basedir/ -iname '*company*' -print0)

This will work with all possible file names, not just ones without whitespace in them.

Presumes bash.

For changing the contents of files I would advise caution because a blind replacement within a file could break things if the file is not plain text. That said, sed was made for this sort of thing.

while IFS= read -d $'\0' -r file ; do
    sed -i '' -e 's/Company/Newcompany/g;s/company/newcompany/g'"$file"
done < <(find /basedir/ -iname '*company*' -print0)

For this run I recommend adding some additional switches to find to limit the files it will process, perhaps

find /basedir/ \( -iname '*company*' -and \( -iname '*.txt' -or -ianem '*.html' \) \) -print0

Upvotes: 0

Fredrik Pihl
Fredrik Pihl

Reputation: 45634

I'd suggest you take a look at man rename an extremely powerful perl-utility for, well, renaming files.

Standard syntax is

rename 's/\.htm$/\.html/' *.htm

the clever part is that the tool accept any perl-regexp as a pattern for a filename to be changed.

you might want to run it with the -n switch which will make the tool to only report what it would have changed.

Can't figure out a nice way to keep the capitalization right now, but since you already can search through the filestructure, issue several rename with different capitalization until all files are changed.

To loop through all files below current folder and to search for a particular string, you can use

find . -type f -exec grep -n -i STRING_TO_SEARCH_FOR /dev/null {} \;

The output from that command can be directed to a file (after some filtering to just extract the file names of the files that need to be changed).

find . /type ... > files_to_operate_on

Then wrap that in a while read loop and do some perl-magic for inplace-replacement

while read file
do
    perl -pi -e 's/stringtoreplace/replacementstring/g' $file
done < files_to_operate_on

Upvotes: 1

Ilmo Euro
Ilmo Euro

Reputation: 5105

bash has powerful looping and substitution capabilities:

for filename in `find /root/of/where/files/are -name *company*`; do
    mv $filename ${filename/company/newcompany}
done
for filename in `find /root/of/where/files/are -name *Company*`; do
    mv $filename ${filename/Company/Newcompany}
done

Upvotes: 1

Didier Trosset
Didier Trosset

Reputation: 37427

For the file and directory names, use for, find, mv and sed.

For each path (f) that has company in the name, rename it (mv) from f to the new name where company is replaced by newcompany.

for f in `find -name '*company*'` ; do mv "$f" "`echo $f | sed s/company/nemcompany/`" ; done

For the file contents, use find, xargs and sed.

For every file, change company by newcompany in its content, keeping original file with extension .backup.

find -type f -print0 | xargs -0 sed -i .bakup 's/company/newcompany/g'

Upvotes: 1

Related Questions