Find Multiple Files and Rename Them in Linux

Find multiple files and rename them in Linux

You can use find to find all matching files recursively:

$ find . -iname "*dbg*" -exec rename _dbg.txt .txt '{}' \;

EDIT: what the '{}' and \; are?

The -exec argument makes find execute rename for every matching file found. '{}' will be replaced with the path name of the file. The last token, \; is there only to mark the end of the exec expression.

All that is described nicely in the man page for find:

 -exec utility [argument ...] ;
True if the program named utility returns a zero value as its
exit status. Optional arguments may be passed to the utility.
The expression must be terminated by a semicolon (``;''). If you
invoke find from a shell you may need to quote the semicolon if
the shell would otherwise treat it as a control operator. If the
string ``{}'' appears anywhere in the utility name or the argu-
ments it is replaced by the pathname of the current file.
Utility will be executed from the directory from which find was
executed. Utility and arguments are not subject to the further
expansion of shell patterns and constructs.

How to rename multiple files in several folders?

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

Find and rename multiple files using a bash script in Linux

The script rename.sh did not use its command line arguments at all, but instead searched files and directories (!) on its own using the glob *.

Change your script to the following.

#!/bin/bash
rename -d s/\''/_/g;
s/[-:"<>@\,&\s\(\)\[\]?!–~%„“;│\´\’\+#]/_/g;
y/A-Z/a-z/;
s/\.(?=[^.]*\.)/_/g;
s/[_]{2,}/_/g' "$@"

Then use find ... -maxdepth 1 -type f -exec sh .../rename.sh {} +.

Changes Made

  • Use "$@" instead of * to process the files given as arguments rather than everything in the current directory.
  • Execute rename only once as a 2nd rename wouldn't find the files specified with "$@" after they were renamed by the 1st rename.
  • Use the -d option such that only the basenames are modified. find always puts a path in front of the files, at the very least ./. Without this option rename would change ./filename to mangledPath/newFilename and therefore move the file to another directory.

Note that man rename is a bit misleading

--path, --fullpath
Rename full path: including any directory component. DEFAULT

-d, --filename, --nopath, --nofullpath
Do not rename directory: only rename filename component of path.

For a given path rename -d 's...' some/path/basename just processes the basename and ignores the leading components some/path/. If basename is a directory it will still be renamed despite the -d option.

How can i find and rename multiple files

Possible solution with Perl rename:

find /mydir -depth -type f -exec rename -v 's/(.*\/)?([^.]*)/$1\U$2/' {} +

The commands in the question have several problems.

You seem to confuse the syntax of find's -exec action and xargs.

find /mydir -depth -type f -exec rename -v 'substitution_command' {} \;
find /mydir -depth -type f| xargs -n 1 rename -v 'substitution_command'

The xargs version has problems in case a file name contains a space.

If you replace \; with +, multiple file names are passed to one invocation of rename.


The substitution command is only supported by the Perl version of the rename command. You might have to install this version. See Get the Perl rename utility instead of the built-in rename


The substitution did not work in my test. I successfully used

rename -v 's/(.*\/)?([^.]*)/$1\U$2/' file ...

The first group (.*\/)? optionally matches a sequence of characters with a trailing /. This is used to copy the directory unchanged.

The second group ([^.]*) matches a sequence of characters except ..

This is the file name part before the first dot (if any) which will be converted to uppercase. In case the file name has more than one extension, all will remain unchanged, e.g.

Path/To/Foo.Bar.Baz -> Path/To/FOO.Bar.Baz

Rename multiple files?

use find:

find /path -depth -name "*.php" -exec sh -c 'mv "$1" "${1%.php}.html"' _ {} \;

How to rename a bunch of files

You can use the rename command as shown below:

rename NCI_ NCIB_ *

Check the screenshot for sample output.

Sample Image

Recursively rename files using find and sed

This happens because sed receives the string {} as input, as can be verified with:

find . -exec echo `echo "{}" | sed 's/./foo/g'` \;

which prints foofoo for each file in the directory, recursively. The reason for this behavior is that the pipeline is executed once, by the shell, when it expands the entire command.

There is no way of quoting the sed pipeline in such a way that find will execute it for every file, since find doesn't execute commands via the shell and has no notion of pipelines or backquotes. The GNU findutils manual explains how to perform a similar task by putting the pipeline in a separate shell script:

#!/bin/sh
echo "$1" | sed 's/_test.rb$/_spec.rb/'

(There may be some perverse way of using sh -c and a ton of quotes to do all this in one command, but I'm not going to try.)

find a pattern in files and rename them

You are echo'ing your 'mv' command, not actually executing it. Change to:

find . -name '*-GHBAG-*' -exec bash -c 'mv $0 ${0/GHBAG/stream-agg}' {} \;

How to rename multiple files with the same name when moving them from all subdirectories into one new location

A bit of find and awk could produce the list of mv commands you need. Let's first assume that your log files have quiet names without newline characters:

find . -type f -name "raml-proxy.log" |
awk -v dir="raml_log_files" '{s=$0; sub(/.*\//,""); n[$0]++;
printf("mv \"%s\" \"%s/%s.%d\"\n", s, dir, $0, n[$0])}' > rename.sh

And then, after careful inspection of file rename.sh, just execute it. Explanation: sub(/.*\//,"") removes the directory part, if any, from the current record, including the last / character. n is an associative array where the keys are the log file names and the values are a counter that increments each time a log file with that name is encountered. Demo:

$ mkdir -p a b c d
$ touch a/a b/a c/a d/b
$ find . -type f | awk -v dir="raml_log_files" '{s=$0; sub(/.*\//,""); n[$0]++;
printf("mv \"%s\" \"%s/%s.%d\"\n", s, dir, $0, n[$0])}'
mv "./b/a" "raml_log_files/a.1"
mv "./a/a" "raml_log_files/a.2"
mv "./d/b" "raml_log_files/b.1"
mv "./c/a" "raml_log_files/a.3"

If there can be newline characters in the names of your log files we can use the NUL character as record separator, instead of the newline:

find . -type f -name "raml-proxy.log" -print0 |
awk -v dir="raml_log_files" -v RS=$'\\0' '{s=$0; sub(/.*\//,""); n[$0]++;
printf("mv \"%s\" \"%s/%s.%d\"\n", s, dir, $0, n[$0])}' > rename.sh


Related Topics



Leave a reply



Submit