Get the Perl rename utility instead of the built-in rename
I can only speak for Debian. The two programs are called
/usr/bin/rename.ul
from theutil-linux
package (hence the .ul suffix)/usr/bin/prename
from theperl
package
The actual rename
command works via the /etc/alternatives
mechanism, whereby
/usr/bin/rename
is a symlink to/etc/alternatives/rename
/etc/alternatives/rename
is a symlink to/usr/bin/prename
The same problem has been bugging me on Cygwin, which is a Red Hat product, so should be more similar to Fedora. I'll have a look on my company laptop on Monday. And I remember the Perl-rename having worked there sometimes. Probably before I installed util-linux
.
If you install the Perl-rename to /usr/local/bin
it will have precedence over rename
from util-linux
. Same goes for the manpage when installed to /usr/local/share/man/man1/
.
I've just created a separate Perl-rename package on Github: https://github.com/subogero/rename
Using the perl-based rename command to change filenames commencing with dashes
Many commands, including Perl's rename
script, support a double-dash to denote the end of a command's options. Hence, to rename --the-file-name
to the-file-name
:
rename 's/-//g' -- --the-file-name
Perl's Getopt::Long module supports this and is used by rename
.
In general, see also: https://unix.stackexchange.com/questions/11376/what-does-double-dash-mean-also-known-as-bare-double-dash
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 -n option seems not available under cygwin
On Cygwin
rename
program comes from util-linux
, see the bottom of man rename
:
The rename command is part of the util-linux package and is available
from ftp://ftp.kernel.org/pub/linux/utils/util-linux/.
On some (most?) Linux distributions rename
is a short Perl
script. If you have Perl
installed on your Cygwin
installation just copy rename
script and run it.
Bulk renaming files with bash and Perl based on file name
In bash, you could write something like:
for file in *-\(ab-[0-9]*\)*; do
newfile="${file/-(ab-[0-9]*)/}"
mv "$file" "$newfile"
done
user perl's rename in Windows cmd.exe, like in linux/bash?
If calling a perl script for your renaming needs is good enough for you on Linux, they why not do it on Windows too? Both ActiveState & Strawberry will modify your registry to associate .pl files with their implementation of perl.
Copy the script to Windows, add a .pl extension & make sure it's in your PATH.
If you'd like to call it without typing in the '.pl' then you can even tell windows that .pl is an 'executable extension' with the PATHEXT environment variable. Of course if you do this then you should heed the warning below & use a name that doesn't conflict with the OS built-ins. (Good catch, Ikegami)
Renaming and Moving Files in Bash or Perl
As per OP, this can be Perl, not just bash. Here we go
NEW SOLUTION: (paying attention to extension)
~/junk/a1$ ls
f1.txt f2.txt f3.txt z1 z2
~/junk/a1$ ls ../a2
f1.txt f2.1.txt f2.2.txt f2.3.txt f2.txt z1
# I split the one-liner into multiple lines for readability
$ perl5.8 -e
'{use strict; use warnings; use File::Copy; use File::Basename;
my @files = glob("*"); # assume current directory
foreach my $file (@files) {
my $file_base2 = basename($file);
my ($file_base, $ext) = ($file_base2 =~ /(.+?)([.][^.]+$)?$/);
my $new_file_base = "../a2/$file_base";
my $new_file = $new_file_base . $ext;
my $counter = 1;
while (-e $new_file) {
$new_file = "$new_file_base." . $counter++ . $ext;
}
copy($file, $new_file)
|| die "could not copy $file to $new_file: $!\n";
} }'
~/junk/a1> ls ../a2
f1.1.txt f1.txt f2.1.txt f2.2.txt f2.3.txt f2.4.txt f2.txt f3.txt
z1 z1.1 z2
OLD SOLUTION: (not paying attention to extension)
~/junk/a1$ ls
f1 f2 f3
~/junk/a1$ ls ../a2
f1 f2 f2.1 f2.2 f2.3
# I split the one-liner into multiple lines for readability
$ perl5.8 -e
'{use strict; use warnings; use File::Copy; use File::Basename;
my @files = glob("*"); # assume current directory
foreach my $file (@files) {
my $file_base = basename($file);
my $new_file_base = "../a2/$file_base";
my $new_file = $new_file_base;
my $counter = 1;
while (-e $new_file) { $new_file = "$new_file_base." . $counter++; }
copy($file,$new_file)
|| die "could not copy $file to $new_file: $!\n";
} }'
~/junk/a1> ls ../a2
f1 f1.1 f2 f2.1 f2.2 f2.3 f2.4 f3
Related Topics
How to Show All Shared Libraries Used by Executables in Linux
Performing Http Requests With Curl (Using Proxy)
Sorting Multiple Keys With Unix Sort
Setting Environment Variables in Linux Using Bash
Linux Default Behavior of Executable .Data Section Changed Between 5.4 and 5.9
How to Redirect Output of Systemd Service to a File
How to Ensure Only One Instance of a Bash Script Is Running
How to Get Cmake to Find My Alternative Boost Installation
How to Loop Over the Output of a Shell Command
Bash Script Process Substitution Syntax Error: "(" Unexpected
Git Asks For Username Every Time I Push
Redirect Stderr/Stdout of a Process After It's Been Started, Using Command Line