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.
23 #include <sys/types.h>
29 #include "closestream.h"
32 #define RENAME_EXIT_SOMEOK 2
33 #define RENAME_EXIT_NOTHING 4
34 #define RENAME_EXIT_UNEXPLAINED 64
36 static int string_replace(char *from
, char *to
, char *s
, char *orig
, char **newname
)
40 where
= strstr(s
, from
);
44 *newname
= xmalloc(strlen(orig
) + strlen(to
) + 1);
51 p
= where
+ strlen(from
);
58 static int ask(char *name
)
62 printf(_("%s: overwrite `%s'? "), program_invocation_short_name
, name
);
64 if ((c
= fgetc(stdin
)) == EOF
) {
66 clearerr(stdin
); errno
= 0;
70 buf
[0] = c
; buf
[1] = '\0';
72 while ((c
= fgetc(stdin
)) != '\n' && c
!= EOF
);
74 if (rpmatch(buf
) == RPMATCH_YES
)
80 static int do_symlink(char *from
, char *to
, char *s
, int verbose
, int noact
,
81 int nooverwrite
, int interactive
)
83 char *newname
= NULL
, *target
= NULL
;
87 if ( faccessat(AT_FDCWD
, s
, F_OK
, AT_SYMLINK_NOFOLLOW
) != 0 &&
89 /* Skip if AT_SYMLINK_NOFOLLOW is not supported; lstat() below will
90 detect the access error */
92 warn(_("%s: not accessible"), s
);
96 if (lstat(s
, &sb
) == -1) {
97 warn(_("stat of %s failed"), s
);
100 if (!S_ISLNK(sb
.st_mode
)) {
101 warnx(_("%s: not a symbolic link"), s
);
104 target
= xmalloc(sb
.st_size
+ 1);
105 if (readlink(s
, target
, sb
.st_size
+ 1) < 0) {
106 warn(_("%s: readlink failed"), s
);
110 target
[sb
.st_size
] = '\0';
111 if (string_replace(from
, to
, target
, target
, &newname
))
114 if (ret
== 1 && (nooverwrite
|| interactive
) && lstat(newname
, &sb
) != 0)
115 nooverwrite
= interactive
= 0;
118 (nooverwrite
|| (interactive
&& (noact
|| ask(newname
) != 0))) )
121 printf(_("Skipping existing link: `%s' -> `%s'\n"), s
, target
);
126 if (!noact
&& 0 > unlink(s
)) {
127 warn(_("%s: unlink failed"), s
);
129 } else if (!noact
&& symlink(newname
, s
) != 0) {
130 warn(_("%s: symlinking to %s failed"), s
, newname
);
134 if (verbose
&& (noact
|| ret
== 1))
136 printf("%s: `%s' -> `%s'\n", s
, target
, newname
);
142 static int do_file(char *from
, char *to
, char *s
, int verbose
, int noact
,
143 int nooverwrite
, int interactive
)
145 char *newname
= NULL
, *file
=NULL
;
148 if (access(s
, F_OK
) != 0) {
149 warn(_("%s: not accessible"), s
);
153 if (strchr(from
, '/') == NULL
&& strchr(to
, '/') == NULL
)
154 file
= strrchr(s
, '/');
157 if (string_replace(from
, to
, file
, s
, &newname
))
160 if ((nooverwrite
|| interactive
) && access(newname
, F_OK
) != 0)
161 nooverwrite
= interactive
= 0;
163 if (nooverwrite
|| (interactive
&& (noact
|| ask(newname
) != 0))) {
165 printf(_("Skipping existing file: `%s'\n"), newname
);
168 else if (!noact
&& rename(s
, newname
) != 0) {
169 warn(_("%s: rename to %s failed"), s
, newname
);
172 if (verbose
&& (noact
|| ret
== 1))
173 printf("`%s' -> `%s'\n", s
, newname
);
178 static void __attribute__((__noreturn__
)) usage(void)
181 fputs(USAGE_HEADER
, out
);
183 _(" %s [options] <expression> <replacement> <file>...\n"),
184 program_invocation_short_name
);
186 fputs(USAGE_SEPARATOR
, out
);
187 fputs(_("Rename files.\n"), out
);
189 fputs(USAGE_OPTIONS
, out
);
190 fputs(_(" -v, --verbose explain what is being done\n"), out
);
191 fputs(_(" -s, --symlink act on the target of symlinks\n"), out
);
192 fputs(_(" -n, --no-act do not make any changes\n"), out
);
193 fputs(_(" -o, --no-overwrite don't overwrite existing files\n"), out
);
194 fputs(_(" -i, --interactive prompt before overwrite\n"), out
);
195 fputs(USAGE_SEPARATOR
, out
);
196 printf(USAGE_HELP_OPTIONS(21));
197 printf(USAGE_MAN_TAIL("rename(1)"));
201 int main(int argc
, char **argv
)
204 int i
, c
, ret
= 0, verbose
= 0, noact
= 0, nooverwrite
= 0, interactive
= 0;
205 int (*do_rename
)(char *from
, char *to
, char *s
, int verbose
, int noact
,
206 int nooverwrite
, int interactive
) = do_file
;
208 static const struct option longopts
[] = {
209 {"verbose", no_argument
, NULL
, 'v'},
210 {"version", no_argument
, NULL
, 'V'},
211 {"help", no_argument
, NULL
, 'h'},
212 {"no-act", no_argument
, NULL
, 'n'},
213 {"no-overwrite", no_argument
, NULL
, 'o'},
214 {"interactive", no_argument
, NULL
, 'i'},
215 {"symlink", no_argument
, NULL
, 's'},
219 setlocale(LC_ALL
, "");
220 bindtextdomain(PACKAGE
, LOCALEDIR
);
222 atexit(close_stdout
);
224 while ((c
= getopt_long(argc
, argv
, "vsVhnoi", longopts
, NULL
)) != -1)
241 do_rename
= do_symlink
;
244 printf(UTIL_LINUX_VERSION
);
249 errtryhelp(EXIT_FAILURE
);
256 warnx(_("not enough arguments"));
257 errtryhelp(EXIT_FAILURE
);
263 if (!strcmp(from
, to
))
264 return RENAME_EXIT_NOTHING
;
266 for (i
= 2; i
< argc
; i
++)
267 ret
|= do_rename(from
, to
, argv
[i
], verbose
, noact
, nooverwrite
, interactive
);
271 return RENAME_EXIT_NOTHING
;
277 return RENAME_EXIT_SOMEOK
;
279 return RENAME_EXIT_UNEXPLAINED
;