Home » Questions » Computers [ Ask a new question ]

BASH: Working with multiple files and directories

BASH: Working with multiple files and directories

I've got about 15 lots of 100+ directories, specifically using pseudocode how can you:

Asked by: Guest | Views: 272
Total answers/comments: 3
Guest [Entry]

"Many linux/unix systems come with a rename or rename.pl or prename perl-script that allows renaming via perl expressions. On Debian systems, it's installed with the perl package.

$ rename
Usage: rename [-v] [-n] [-f] perlexpr [filenames]

The magic happens in the perlexpr argument. This is essentially a short bit of perl code that will operate on each filename. You don't need to provide any loops, just write code that transforms your input into the desired output. (Be sure and quote the expression; I use single-quotes to protect against shell expansion unless it's absolutely necessary.)

So, for your examples:

rename * *suffix

$ rename 's/$/suffix/' *
^ ^ ^^^^
| | +-- your suffix goes here
| +------- indicates end-of-string
+--------- perl's substitution operator (s/from-regex/to/)

rename * prefix*

$ rename 's/^/prefix/' *
^ ^^^^
| +-- your prefix goes here
+------- indicates beginning-of-string

rename * CAPITALIZE*

$ rename '$_ = uc' *
^^^^ ^^
| +-- perl builtin function to capitalize a string
+------- replaces input filename

See more examples from the O'Reilly Unix Power Tools book."
Guest [Entry]

"I'd use Perl - and specifically this modified version of a 'rename' script that was in the 1st Edition of the Camel book (but dropped from the second and third editions for lack of space).

Usage:

find . -type f -print0 | xargs -0 rename 's%/([^/]+)$%/prefix\U${1}\Esuffix%'

Which, being translated, means:

find all the files, even those with blanks in their name, and handle them properly.
for each file name, find the name after the last slash, remembering it as '${1}'
replace the name with 'prefix', the upper-case version of what was remembered, and 'suffix'

So, the whole job can be done in one command with a sufficiently versatile tool.

#!/Users/jleffler/perl/v5.10.0/bin/perl -w
#
# @(#)$Id: rename.pl,v 1.7 2008/02/16 07:53:08 jleffler Exp $
#
# Rename files using a Perl substitute or transliterate command

use strict;
use Getopt::Std;

my(%opts);
my($usage) = ""Usage: $0 [-fnxV] perlexpr [filenames]\n"";
my($force) = 0;
my($noexc) = 0;
my($trace) = 0;

die $usage unless getopts('fnxV', \%opts);

if ($opts{V})
{
printf ""%s\n"", q'RENAME Version $Revision: 1.7 $ ($Date: 2008/02/16 07:53:08 $)';
exit 0;
}
$force = 1 if ($opts{f});
$noexc = 1 if ($opts{n});
$trace = 1 if ($opts{x});

my($op) = shift;
die $usage unless defined $op;

if (!@ARGV) {
@ARGV = <STDIN>;
chop(@ARGV);
}

for (@ARGV)
{
if (-e $_ || -l $_)
{
my($was) = $_;
eval $op;
die $@ if $@;
next if ($was eq $_);
if ($force == 0 && -f $_)
{
print STDERR ""rename failed: $was - $_ exists\n"";
}
else
{
print ""+ $was --> $_\n"" if $trace;
print STDERR ""rename failed: $was - $!\n""
unless ($noexc || rename($was, $_));
}
}
else
{
print STDERR ""$_ - $!\n"";
}
}

For whatever it is worth, I ran into a persistent failure that was not dreadfully informative when I tried:

$ find . -type f -print0 | xargs -0 rename 's/.*/prefix$&suffix/'
rename failed: ./xxx-32 - No such file or directory
rename failed: ./xxx-64 - No such file or directory
rename failed: ./xxx.c - No such file or directory
rename failed: ./xxx.c~ - No such file or directory
$

That was odd - I can see those files...

Using the '-x' option to 'rename' told me what the trouble was, though:

rename failed: ./xxx-32 - No such file or directory
rename failed: ./xxx-64 - No such file or directory
rename failed: ./xxx.c - No such file or directory
rename failed: ./xxx.c~ - No such file or directory
+ ./xxx-32 --> prefix./xxx-32suffix
+ ./xxx-64 --> prefix./xxx-64suffix
+ ./xxx.c --> prefix./xxx.csuffix
+ ./xxx.c~ --> prefix./xxx.c~suffix

Oh right - there isn't a sub-directory called 'prefix.' in my current directory!"
Guest [Entry]

"This rename perl script evaluates the first argument as code to rename the files given with the rest of the arguments.

#!/usr/bin/perl

($op = shift) || die ""Usage: $0 perlexpr [filenames]\n"";
if (!@ARGV) {
@ARGV = <STDIN>;
chop(@ARGV);
}
for (@ARGV) {
$was = $_;
eval $op;
die $@ if $@;
rename($was,$_) unless $was eq $_;
}"