5 vidir - edit directories and filenames
9 B<vidir> [B<--verbose>] [I<directory>|I<file>|B<->]...
13 B<vidir> allows editing of directories and filenames in a text editor. If no
14 I<directory> is specified, the filenames of the current directory are edited.
16 When editing a directory, each item in the directory will appear on its own
17 numbered line. These numbers are how vidir keeps track of what items are
18 changed. Delete lines to remove files from the directory, or
19 edit filenames to rename files. You can also switch pairs of numbers to
22 Filenames to be edited may be given any combination of I<directory>s (which
23 will be expanded to the non-recursive list of all files within I<directory>),
24 I<file>s, or I<->. If the latter is specified, B<vidir> reads a list of
25 filenames from stdin and displays those for editing.
33 Verbosely display the actions taken by the program.
49 Edit subdirectory contents too. To delete subdirectories,
50 delete all their contents and the subdirectory itself in the editor.
52 =item find -type f | vidir -
54 Edit all files under the current directory and subdirectories.
58 =head1 ENVIRONMENT VARIABLES
68 Also supported to determine what editor to use.
74 Copyright 2006 by Joey Hess <id@joeyh.name>
76 Licensed under the GNU GPL.
81 use File
::Path
qw(make_path);
89 if (! GetOptions
("verbose|v" => \
$verbose)) {
90 die "Usage: $0 [--verbose] [directory|file|-]\n";
97 foreach my $item (@ARGV) {
99 push @dir, map { chomp; $_ } <STDIN
>;
101 open(STDIN
, "/dev/tty") || die "reopen: $!\n";
105 opendir(DIR
, $item) || die "$0: cannot read $item: $!\n";
106 push @dir, map { "$item$_" } sort readdir(DIR
);
114 if (grep(/[[:cntrl:]]/, @dir)) {
115 die "$0: control characters in filenames are not supported\n";
118 my $tmp=File
::Temp
->new(TEMPLATE
=> "dirXXXXX", DIR
=> File
::Spec
->tmpdir);
119 open (OUT
, ">".$tmp->filename) || die "$0: cannot create ".$tmp->filename.": $!\n";
123 my $l = $#dir =~ tr/0-9//;
125 next if /^(.*\/)?\
.$/ || /^(.*\
/)?\.\.$/;
127 printf OUT
"%0*d\t%s\n", $l, $c, $_;
130 close OUT
|| die "$0: cannot write ".$tmp->filename.": $!\n";
133 if (-x
"/usr/bin/editor") {
134 @editor="/usr/bin/editor";
136 if (exists $ENV{EDITOR
}) {
137 @editor=split(' ', $ENV{EDITOR
});
139 if (exists $ENV{VISUAL
}) {
140 @editor=split(' ', $ENV{VISUAL
});
142 $ret=system(@editor, $tmp);
144 die "@editor exited nonzero, aborting\n";
147 open (IN
, $tmp->filename) || die "$0: cannot read ".$tmp->filename.": $!\n";
150 if (/^(\d+)\t{0,1}(.*)/) {
153 if (! exists $item{$num}) {
154 die "$0: unknown item number $num\n";
156 elsif ($name ne $item{$num}) {
157 next unless length $name;
159 my $dir=dirname
($name);
161 if (! (-e
$src || -l
$src) ) {
162 print STDERR
"$0: $src does not exist\n";
168 if (-e
$name || -l
$name) {
171 while (-e
$tmp || -l
$tmp) {
175 if (! rename($name, $tmp)) {
176 print STDERR
"$0: failed to rename $name to $tmp: $!\n";
180 print "'$name' -> '$tmp'\n";
182 foreach my $item (keys %item) {
183 if ($item{$item} eq $name) {
189 if ((! -d
$dir) && (! make_path
($dir, {
192 print STDERR
"$0: failed to create directory tree $dir: $!\n";
195 elsif (! rename($src, $name)) {
196 print STDERR
"$0: failed to rename $src to $name: $!\n";
201 foreach (values %item) {
202 s
,^\Q
$src\E
($|/),$name$1,;
206 print "'$src' => '$name'\n";
216 die "$0: unable to parse line \"$_\", aborting\n";
219 close IN
|| die "$0: cannot read ".$tmp->filename.": $!\n";
220 unlink($tmp.'~') if -e
$tmp.'~';
225 if (-d
$file && ! -l
$file) {
233 foreach my $item (reverse sort values %item) {
235 print STDERR
"$0: failed to remove $item: $!\n";
239 print "removed '$item'\n";