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 inputchomp
clean a newline$f
is new filename, same as old filenames/\/file/\/doc/
replace "/file" with "/doc" in the new filenamemv $_ $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 2ndrename
wouldn't find the files specified with"$@"
after they were renamed by the 1strename
. - 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 optionrename
would change./filename
tomangledPath/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.
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
Why Are the Backslash and Semicolon Required With the Find Command'S -Exec Option
&&' Vs. '&' With the 'Test' Command in Bash
Bluez: How to Set Up a Gatt Server from the Command Line
How to Single Step Arm Assembly in Gdb on Qemu
Can _Start Be the Thumb Function
Given Two Directory Trees, How to Find Out Which Files Differ by Content
How to Use 'Cp' Command to Exclude a Specific Directory
How to Create a File With a Given Size in Linux
How to Run Multiple Background Commands in Bash in a Single Line
Does Malloc Lazily Create the Backing Pages For an Allocation on Linux (And Other Platforms)
Use Bluez Stack as a Peripheral (Advertiser)
Externalizing Tomcat Webapp Config from .War File
Bash Alias Command With Both Single and Double Quotes
Maximum Length of Command Line Argument That Can Be Passed to Sql*Plus
How to Remove the Last Character of a File in Unix
Run a Shell Command When a File Is Added
How to Remove ^[, and All of the Escape Sequences in a File Using Linux Shell Scripting