/
perlmv
241 lines (171 loc) · 6.87 KB
/
perlmv
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
#!/usr/bin/perl
use strict;
use warnings;
use FindBin '$Bin';
use lib "$Bin/../lib";
use App::perlmv;
my $pmv = App::perlmv->new;
$pmv->{ 'mode' } = 'rename';
$pmv->run;
1;
# ABSTRACT: Rename files using Perl code
# PODNAME: perlmv
=head1 SYNOPSIS
Usage:
# Show help
perlmv -h
# Execute a single scriptlet
perlmv [options] <scriptlet> <file...>
# Execute code from command line
perlmv [options] -e <code> <file...>
# Execute multiple scriptlets/command-line codes
perlmv [options] [ -x <scriptlet> | -e <code> ]+ <file...>
# Create a new scriptlet
perlmv -e <code> -w <name>
# List available scriptlets
perlmv -l
# Show source code of a scriptlet
perlmv -s <name>
# Delete scriptlet
perlmv -d <name>
=head2 Usage examples
$ ls -1
A.txt
B1
c2.txt
D3.pl
D4.pl
Rename files with prewritten scriptlet (B<remove-common-prefix>) and show (B<-v>)
each file as it is being renamed.
$ perlmv -v remove-common-prefix file1.jpg file2.zip files.txt
`file1.jpg` -> `1.jpg`
`file2.zip` -> `2.zip`
`files.txt` -> `s.txt`
Specify script in command line (B<-e>) but do not actually rename files (B<-d>,
dry-run mode):
$ perlmv -de 's/\d+//g' *
DRYRUN: `B1` -> `B`
DRYRUN: `c2.txt` -> `c.txt`
DRYRUN: `D3.pl` -> `D.pl`
DRYRUN: `D4.pl` -> `D.pl.1`
Really rename the files this time:
$ perlmv -e 's/\d+//g' *
Execute multiple scriptlets and/or command-line code:
$ ls -1
a.txt
b.html
c.ini
$ perlmv -vx to-number-ext -e '"file$_"' *
`a.txt` -> `1.txt` -> `file1.txt`
`b.html` -> `2.html` -> `file2.html`
`c.ini` -> `3.ini` -> `file3.ini`
Save Perl code as scriptlet (in ~/.perlmv/scriptlets/):
$ perlmv -e 's/\d+//g' -w remove-digits
List all scriptlets (add B<-v> to also show their contents):
$ perlmv -l
lc
uc
remove-digits
Show (B<-s>) source code of scriptlet:
$ perlmv -s remove-digits
s/\d+//g
Remove (B<-D>) scriptlet:
$ perlmv -D remove-digits
=head2 More examples
From my real-world usage.
Rename .flv partial files from my Firefox browser cache into ordered names
(part01.flv, part02.flv, and so on):
$ ls --sort=t -r *01 | xargs perlmv -Tdx to-number-ext -e '"part$_.flv"'
DRYRUN: `15D9F85Ad01` -> `01` -> `part01.flv`
DRYRUN: `FF8EB240d01` -> `02` -> `part02.flv`
DRYRUN: `9031E9A8d01` -> `03` -> `part03.flv`
...
=head1 DESCRIPTION
Perlmv lets you rename files using Perl code. All the Perl code needs to do is
modify the filename in C<$_> (or just return a value) and perlmv will do the rest
(actual renaming, recursive renaming, handling filename conflicts, dry-run mode,
etc.).
New filename will be taken from the new value of $_ (if it is modified) or the
last expression. So '$_ = lc' and 'lc' are equivalent.
The following variables are also available to the Perl code:
=over 4
=item * C<$FILES> (arrayref)
The list of items to be processed. The Perl code is not supposed to modify this
value.
=item * C<$FILE> (string)
The filename of item (without path). The Perl code is not supposed to modify
this value.
=item * C<$DIR> (string)
The directory of item (absolute path). The Perl code is not supposed to modify
this value.
=item * C<$PARENT> (string)
The name of parent (containing) directory of the item (without path). The Perl
code is not supposed to modify this value.
=back
Perl code will first be run (eval-ed) once at the beginning for testing, with
C<-TEST> as the filename in C<$_> (and C<$TESTING> will be set to true). Perl
code is not run under strict/warnings. Perl code is run under
C<App::perlmv::code> namespace.
When using the L<App::perlmv> library, there is also the the so-called cleaning
phase (in which Perl code will be run with $CLEANING set to true) that can be
used for cleaning purposes in between runs (call to rename()). This is however
irrelevant to B<perlmv> command as B<perlmv> only calls rename() once.
Perl code can be specified directly from the command line (using B<-e>), or by
name in C<~/.perlmv/scriptlets/NAME>, or in C</usr/share/perlmv/scriptlets/>, or
in C<%scriptlets> in L<App::perlmv::scriptlets>, or in C<%scriptlets> in
L<App::perlmv::scriptlets::std>.
=head1 OPTIONS
-c (--compile) Only test compile code, do not run it on the arguments
-D <NAME> (--delete) Delete scriptlet
-d (--dry-run) Dry-run (implies -v)
-e <CODE> (--execute) Specify Perl code to rename file (\$_). Can be specified
multiple times.
-f (--files) Only process files, do not process directories
-h (--help) Show this help
-l (--list) list all scriptlets
-M <MODE> (--mode) Specify mode, default is 'rename' (or 'r'). Use 'copy' or 'c'
to copy instead of rename, 'symlink' or 's' to create a symbolic link, and
'link' or 'l' to create a (hard) link.
-o (--overwrite) Overwrite (by default, ".1", ".2", and so on will be appended
to avoid overwriting existing files)
-p (--parents) Create intermediate directories
-R (--recursive) Recursive
-r (--reverse) reverse order of processing (by default order is asciibetically)
-S (--no-symlinks) Do not process symlinks
-s <NAME> (--show) Show source code for scriptlet
-T (--no-sort) do not sort files (default is sort ascibetically)
-V (--version) Print version and exit
-v (--verbose) Verbose
-w <NAME> (--write) Write code specified in -e as scriptlet
-x <NAME> Execute a scriptlet. Can be specified multiple times. -x is optional
if there is only one scriptlet to execute, and scriptlet name is specified
as the first argument, and there is no -e specified.
=head1 FAQ
=head2 Why should I use perlmv? There is prename (File::Rename) already?
Yes, there is a very similar script called B<prename> (also accessible via
B<rename> in Debian) which comes with Perl. This script reinvents prename and
offers more features, e.g.: automatic renaming in case of conflicts, recursive
mode, and saving and loading scriptlets.
=head2 And there is also pmv (File::PerlMove)!
Okay, you got me. I didn't do my homework. The "rename files using Perl
code/expression" is pretty obvious and has surely come up on other CPAN authors'
minds. To be honest, this is a script which I wrote years ago (at least in 2003,
or earlier) and have been using for years, personally. Admittedly I uploaded this
script to CPAN without careful checking of existing solutions on CPAN. But then,
lots of other CPAN modules are also overlapping in functionality with one
another.
Anyway, I plan to improve perlmv as I see fit, mainly for my own needs. I plan to
borrow some features from prename/pmv, and welcome them borrowing features from
perlmv. I welcome patches. And I am willing to submit patches to prename/pmv
after some discussions with the respective authors. And lastly, I am also open to
the idea of merging perlmv to either pername/pmv, if I can get all the features I
love in perlmv into those projects.
=head1 BUGS/TODOS
=over 4
=item * Patches for Windows welcome.
=item * Scriptlet should be able to receive arguments.
=back
=head1 SEE ALSO
L<prename> (L<File::Rename>)
L<pm> (L<File::PerlMove>)
=cut