Home > Net >  How to rename multiple files in several folders?
How to rename multiple files in several folders?

Time:09-17

I'd like to rename all files in several folders with filename containing '*file*' by '*doc*'. I've tried

find . -name "*file*" -exec mv {} `echo {} | sed "s/file/doc/"` \;

but got an error (see below).

~$ ls
my_file_1.txt  my_file_2.txt  my_file_3.txt

~$ find . -name "*file*"
./my_file_1.txt
./my_file_3.txt
./my_file_2.txt

~$ echo my_file_1.txt | sed "s/file/doc/"
my_doc_1.txt

~$ find . -name "*file*" -exec echo {} \;
./my_file_1.txt
./my_file_3.txt
./my_file_2.txt

~$ find . -name "*file*" -exec mv {} `echo {} | sed "s/file/doc/"` \;
mv: './my_file_1.txt' and './my_file_1.txt' are the same file
mv: './my_file_3.txt' and './my_file_3.txt' are the same file
mv: './my_file_2.txt' and './my_file_2.txt' are the same file

Many thanks for your help!

CodePudding user response:

There are a thousand ways to do it, I'd do it with Perl, something like this will work:

find files -type f -name "file*" | perl -ne 'chomp; $f=$_; $f=~s/\/file/\/doc/; `mv $_  $f`;'
  • -ne process as inline script for each line input
  • chomp clean a newline
  • $f is new filename, same as old filename
  • s/\/file/\/doc/ replace "/file" with "/doc" in the new filename
  • mv $_ $f rename the file by running an OS command with back ticks

CodePudding user response:

The problem with your solution is that the echo {} | sed "s/file/doc/" is executed before the rest of the find command. I tried to make a command demonstrating this:

find . -name "." -exec date \; -exec echo `date; sleep 5` \;

When the date commands aare executed from left to right, the dates would be equal. However the second date and the sleep are executed before find starts the first date.
Result:

Wed Aug 25 22:33:43 XXX 2021
Wed Aug 25 22:33:38 XXX 2021

The following solution is using print0 and xargs -0 for filenames with newlines. xargs will echo the mv command with two additional slashes.
The slashes will be found by the sed command, changing the target filename.
The result of sed is parsed by a new bash shell.

find . -name "*file1*"  -print0 2>/dev/null |
  xargs -0 -I {} echo mv '"{}"' //'"{}"' |
  sed -r 's#//(.*)file(.*)#\1doc\2#' |
  bash

CodePudding user response:

See if you have rename command. If it is perl based:

# -n is for testing, remove it for actual renaming
find -name '*file*' -exec rename -n 's/file/doc/' {}  

If it is not perl based, see if this works:

# remove --no-act --verbose for actual renaming
find -name '*file*' -exec rename --no-act --verbose 'file' 'doc' {}  
  • Related