2 * rename.c - aeb 2000-01-01
4 --------------------------------------------------------------
6 if [ $# -le 2 ]; then echo call: rename from to files; exit; fi
11 for i in $@; do N=`echo "$i" | sed "s/$FROM/$TO/g"`; mv "$i" "$N"; done
12 --------------------------------------------------------------
13 * This shell script will do renames of files, but may fail
14 * in cases involving special characters. Here a C version.
17 #ifdef HAVE_STDIO_EXT_H
18 # include <stdio_ext.h>
22 # define HAVE___FPURGE 1
23 # define __fpurge fpurge
33 #include <sys/types.h>
39 #include "closestream.h"
42 #define RENAME_EXIT_SOMEOK 2
43 #define RENAME_EXIT_NOTHING 4
44 #define RENAME_EXIT_UNEXPLAINED 64
46 static int tty_cbreak
= 0;
48 static int string_replace(char *from
, char *to
, char *s
, char *orig
, char **newname
)
52 where
= strstr(s
, from
);
56 *newname
= xmalloc(strlen(orig
) + strlen(to
) + 1);
63 p
= where
+ strlen(from
);
70 static int ask(char *name
)
74 printf(_("%s: overwrite `%s'? "), program_invocation_short_name
, name
);
76 if ((c
= fgetc(stdin
)) == EOF
) {
82 if (c
!= '\n' && tty_cbreak
) {
84 /* Possibly purge a multi-byte character; or do a
85 required purge of the rest of the line (including
86 the newline) if the tty has been put back in
87 canonical mode (for example by a shell after a
94 while ((c
= fgetc(stdin
)) != '\n' && c
!= EOF
);
97 if (rpmatch(buf
) == RPMATCH_YES
)
103 static int do_symlink(char *from
, char *to
, char *s
, int verbose
, int noact
,
104 int nooverwrite
, int interactive
)
106 char *newname
= NULL
, *target
= NULL
;
110 if ( faccessat(AT_FDCWD
, s
, F_OK
, AT_SYMLINK_NOFOLLOW
) != 0 &&
112 /* Skip if AT_SYMLINK_NOFOLLOW is not supported; lstat() below will
113 detect the access error */
115 warn(_("%s: not accessible"), s
);
119 if (lstat(s
, &sb
) == -1) {
120 warn(_("stat of %s failed"), s
);
123 if (!S_ISLNK(sb
.st_mode
)) {
124 warnx(_("%s: not a symbolic link"), s
);
127 target
= xmalloc(sb
.st_size
+ 1);
128 if (readlink(s
, target
, sb
.st_size
+ 1) < 0) {
129 warn(_("%s: readlink failed"), s
);
133 target
[sb
.st_size
] = '\0';
134 if (string_replace(from
, to
, target
, target
, &newname
) != 0)
137 if (ret
== 1 && (nooverwrite
|| interactive
) && lstat(newname
, &sb
) != 0)
138 nooverwrite
= interactive
= 0;
141 (nooverwrite
|| (interactive
&& (noact
|| ask(newname
) != 0))) )
144 printf(_("Skipping existing link: `%s' -> `%s'\n"), s
, target
);
149 if (!noact
&& 0 > unlink(s
)) {
150 warn(_("%s: unlink failed"), s
);
153 else if (!noact
&& symlink(newname
, s
) != 0) {
154 warn(_("%s: symlinking to %s failed"), s
, newname
);
158 if (verbose
&& (noact
|| ret
== 1))
159 printf("%s: `%s' -> `%s'\n", s
, target
, newname
);
165 static int do_file(char *from
, char *to
, char *s
, int verbose
, int noact
,
166 int nooverwrite
, int interactive
)
168 char *newname
= NULL
, *file
=NULL
;
171 if (access(s
, F_OK
) != 0) {
172 warn(_("%s: not accessible"), s
);
176 if (strchr(from
, '/') == NULL
&& strchr(to
, '/') == NULL
)
177 file
= strrchr(s
, '/');
180 if (string_replace(from
, to
, file
, s
, &newname
) != 0)
183 if ((nooverwrite
|| interactive
) && access(newname
, F_OK
) != 0)
184 nooverwrite
= interactive
= 0;
186 if (nooverwrite
|| (interactive
&& (noact
|| ask(newname
) != 0))) {
188 printf(_("Skipping existing file: `%s'\n"), newname
);
191 else if (!noact
&& rename(s
, newname
) != 0) {
192 warn(_("%s: rename to %s failed"), s
, newname
);
195 if (verbose
&& (noact
|| ret
== 1))
196 printf("`%s' -> `%s'\n", s
, newname
);
201 static void __attribute__((__noreturn__
)) usage(void)
204 fputs(USAGE_HEADER
, out
);
206 _(" %s [options] <expression> <replacement> <file>...\n"),
207 program_invocation_short_name
);
209 fputs(USAGE_SEPARATOR
, out
);
210 fputs(_("Rename files.\n"), out
);
212 fputs(USAGE_OPTIONS
, out
);
213 fputs(_(" -v, --verbose explain what is being done\n"), out
);
214 fputs(_(" -s, --symlink act on the target of symlinks\n"), out
);
215 fputs(_(" -n, --no-act do not make any changes\n"), out
);
216 fputs(_(" -o, --no-overwrite don't overwrite existing files\n"), out
);
217 fputs(_(" -i, --interactive prompt before overwrite\n"), out
);
218 fputs(USAGE_SEPARATOR
, out
);
219 printf(USAGE_HELP_OPTIONS(21));
220 printf(USAGE_MAN_TAIL("rename(1)"));
224 int main(int argc
, char **argv
)
227 int i
, c
, ret
= 0, verbose
= 0, noact
= 0, nooverwrite
= 0, interactive
= 0;
229 int (*do_rename
)(char *from
, char *to
, char *s
, int verbose
, int noact
,
230 int nooverwrite
, int interactive
) = do_file
;
232 static const struct option longopts
[] = {
233 {"verbose", no_argument
, NULL
, 'v'},
234 {"version", no_argument
, NULL
, 'V'},
235 {"help", no_argument
, NULL
, 'h'},
236 {"no-act", no_argument
, NULL
, 'n'},
237 {"no-overwrite", no_argument
, NULL
, 'o'},
238 {"interactive", no_argument
, NULL
, 'i'},
239 {"symlink", no_argument
, NULL
, 's'},
243 setlocale(LC_ALL
, "");
244 bindtextdomain(PACKAGE
, LOCALEDIR
);
246 atexit(close_stdout
);
248 while ((c
= getopt_long(argc
, argv
, "vsVhnoi", longopts
, NULL
)) != -1)
265 do_rename
= do_symlink
;
268 printf(UTIL_LINUX_VERSION
);
273 errtryhelp(EXIT_FAILURE
);
280 warnx(_("not enough arguments"));
281 errtryhelp(EXIT_FAILURE
);
287 if (!strcmp(from
, to
))
288 return RENAME_EXIT_NOTHING
;
291 if (interactive
&& isatty(STDIN_FILENO
) != 0) {
292 if (tcgetattr(STDIN_FILENO
, &tio
) != 0)
293 warn(_("failed to get terminal attributes"));
294 else if (!(tio
.c_lflag
& ICANON
) && tio
.c_cc
[VMIN
] == 1)
298 for (i
= 2; i
< argc
; i
++)
299 ret
|= do_rename(from
, to
, argv
[i
], verbose
, noact
, nooverwrite
, interactive
);
303 return RENAME_EXIT_NOTHING
;
309 return RENAME_EXIT_SOMEOK
;
311 return RENAME_EXIT_UNEXPLAINED
;