[alt.sources] Neat utility to convert uppercase filenames

jay@gdx.UUCP (Jay A. Snyder) (12/08/90)

Did you ever do mget from simtel20 or ymodem batch downloads from an MSDOS
BBS, and get a lot of uppercase files in your directory?

Well this is a utility that will take all specified files and convert
them to lower case.

One exception is that trailing .Z's will be left uppercase

eg.

% ls
FILE.ZIP  FOO.BAR  TESTARC.TAR

% fdncase *
FILE.ZIP ==> file.zip
FOO.BAR.Z ==> foo.bar
TESTARC.TAR.Z ==> testarc.tar
%

----- snip snip -----
#include <stdio.h>
#include <stdlib.h>

usage()
{
  fprintf(stderr,"fdncase: File DowNcase\n");
  fprintf(stderr,"usage: fdncase file1 file2 ...\n");
  exit(0);
}

char *strtolcpy(d,s)
     char *s,*d;
{
  char *r;
  r=d;
  while (*d++=tolower(*s++));
  return(r);
}

#ifdef SYSV
rename(old,new)
     char *old,*new;
{
  int error;
  if (!(error=link(old,new)))
    {
      unlink(old);
      return(0);
    }
  else
    return error;
}
#endif

main(argc,argv)
     int argc;
     int *argv[];
{
  int i;
  char tmpstr[80];
  if (argc==1) usage();
  for (i=1;i<argc;++i)
    {
      if (strcmp(argv[i],strtolcpy(tmpstr,argv[i])))
	{
	  if (!rename(argv[i],tmpstr))
	    fprintf(stderr,"%s ==> %s\n",argv[i],tmpstr);
	  else
	    fprintf(stderr,"error renaming %s\n",argv[i]);
	}
      else
	{
	  fprintf(stderr,"%s already lower case\n",argv[i]);
	}
    }
}

kjh@pollux.usc.edu (Kenneth J. Hendrickson) (12/08/90)

The following Bourne shell script has always worked well for me:

for file in *
do
	mv -i $file `echo $file | tr A-Z a-z`
done

For Sys V, put square brackets around the tr strings.

-- 
favourite oxymorons:   student athlete, military justice, mercy killing
Ken Hendrickson N8DGN/6       kjh@usc.edu      ...!uunet!usc!pollux!kjh

tchrist@convex.COM (Tom Christiansen) (12/08/90)

Here's one version of rename, a generic utility to 
perform infinite contortions on your filenames.  It's
surely more powerful than anything of its ilk I've
ever seen before.

--tom

#!/usr/bin/perl
#
# rename script examples from lwall:
#       rename 's/\.orig$//' *.orig
#       rename 'y/A-Z/a-z/ unless /^Make/' *
#       rename '$_ .= ".bad"' *.f
#       rename 'print "$_: "; s/foo/bar/ if <stdin> =~ /^y/i' *
#
# shows good use of eval operator

$op = shift;
for (@ARGV) {
    $was = $_;
    eval $op;
    die $@ if $@;
    rename($was,$_) unless $was eq $_;
}

--
Tom Christiansen		tchrist@convex.com	convex!tchrist
"With a kernel dive, all things are possible, but it sure makes it hard
 to look at yourself in the mirror the next morning."  -me

flint@gistdev.gist.com (Flint Pellett) (12/11/90)

jay@gdx.UUCP (Jay A. Snyder) writes:


>Did you ever do mget from simtel20 or ymodem batch downloads from an MSDOS
>BBS, and get a lot of uppercase files in your directory?

>Well this is a utility that will take all specified files and convert
>them to lower case.

>One exception is that trailing .Z's will be left uppercase

Rather a bit of overkill to write a C program for it isn't it?
The script below, hacked out in about 30 seconds, does most of what
want-- adding an -if- to check for the trailing .Z files is left
as an exercise for the reader :-).  You can also add a check for
a $1 that was already all lower case if you want.

#!/bin/ksh
while [ -n "$1" ]
do
    typeset -l LC="$1"
    mv "$1" "${LC}"
    shift
done

I suppose I should offer a (slower) Bourne shell version for
anyone unlucky enough to still be limited to that:  I'm 
sure someone can probably improve on this and make it even
shorter. (You can probably write it in perl in 1 line.)

#!/bin/sh
while [ "$1" != "" ]
do
    mv $1 `echo $1 | tr "[A-Z]" "[a-z]"`
    shift
done
-- 
Flint Pellett, Global Information Systems Technology, Inc.
1800 Woodfield Drive, Savoy, IL  61874     (217) 352-1165
uunet!gistdev!flint or flint@gistdev.gist.com

pinard@IRO.UMontreal.CA (Francois Pinard) (12/11/90)

In article <76@gdx.UUCP> jay@gdx.UUCP (Jay A. Snyder) writes:

   Did you ever do mget from simtel20 or ymodem batch downloads from
   an MSDOS BBS, and get a lot of uppercase files in your directory?
   Well this is a utility that will take all specified files and
   convert them to lower case.

I use this:

#!/bin/sh
# Convert upper case in file names to lower case.
# Copyright (C) 1990 Free Software Foundation, Inc.
# Francois Pinard <pinard@iro.umontreal.ca>, October 1990.

echo $* \
	| tr " " "\012" \
	| gawk '{ if ($1 != tolower($1)) { print "mv", $1, tolower($1) } }' \
	| sh

I'm sure there is a one-liner in Perl to do the same :-).
--
Franc,ois Pinard          ``Vivement GNU!''         pinard@iro.umontreal.ca
(514) 588-4656    cp 886 L'Epiphanie (Qc) J0K 1J0    ...!uunet!iros1!pinard

dhesi%cirrusl@oliveb.ATC.olivetti.com (Rahul Dhesi) (12/11/90)

I think all the programs posted so far have the bug that if you have
files called "x" and "X", they will delete one of them.  Here's mine.
Doesn't disturb files whose names already contain any lowercase
characters (thus preserving names like "Makefile"), and even has online
help!  Not shar'd, cut out and use.

#! /bin/sh
# converts to lowercase
if test $# -lt 1; then
   echo "usage: lfname file ..."
   echo "(specified filenames are converted to lowercase)"
   exit 1
fi

for f in "$@"
do
   case "$f" in
   *[a-z]*)
      #echo "skipping $f, contains lowercase chars"
      ;;
   *)
      newname=`echo "$f" | tr 'A-Z' 'a-z'`
      if test "$newname" != "$f"
      then
	 if test -f "$newname"
	 then
	    echo "$newname already exists"
	 else
	    mv "$f" "$newname"
	 fi
      fi
      ;;
   esac
done
exit 0
--
Rahul Dhesi <dhesi%cirrusl@oliveb.ATC.olivetti.com>
UUCP:  oliveb!cirrusl!dhesi

aipdc@castle.ed.ac.uk (Paul Crowley) (12/11/90)

I'd like to know if there's an "intelligent" casing program out there
that I could feed "BIFF" posts through.  Something that would capitalise
after full stops, and recognise some proper nouns, for example. 
Mixed-case is so much easier to read.
-- 
\/ o\ Paul Crowley aipdc@uk.ac.ed.castle
/\__/ "Trust me, I know what I'm doing" - Sledge Hammer

mitchell (Bill Mitchell) (12/11/90)

In article <2797@cirrusl.UUCP> dhesi%cirrusl@oliveb.ATC.olivetti.com (Rahul Dhesi) writes:

>I think all the programs posted so far have the bug that if you have
>files called "x" and "X", they will delete one of them.  Here's mine.
>
> (shell script deleted)

Yours is similar to the one I was using, until I saw this one posted:

for file in $*
do
	mv -i $file `echo $file | tr A-Z a-z`
done

The mv program typically refuses to overwrite an existing file and, having
failed, leaves the original file in place with its original name.

This is free (that's what I paid for it) and comes with a moneyback
guarantee.  Your mileage may vary.

-- 
mitchell@mdi.com (Bill Mitchell)

tchrist@convex.COM (Tom Christiansen) (12/12/90)

In article <2797@cirrusl.UUCP> dhesi%cirrusl@oliveb.ATC.olivetti.com (Rahul Dhesi) writes:
:I think all the programs posted so far have the bug that if you have
:files called "x" and "X", they will delete one of them.  
:Doesn't disturb files whose names already contain any lowercase
:characters (thus preserving names like "Makefile"), and even has online
:help!  Not shar'd, cut out and use.

This is not a bug -- it's a feature.  Anyway, I've added a -i flag to
lwall's rename script to emulate mv's behavior (although I don't believe
in exiting !0 just because you said 'n'.).

And this one is as self-documenting as they can come. :-)

Again, this is a *generic* filename munging tool.  It'll do anything you
could ever want to the filename, not just what you've thought of today.
The "leave Makefiles alone" isn't special cased in, but see the examples.

Again, not sharred, even if it kinda looks like it.  Perl magic, you know.

--tom

#!/usr/bin/perl
'di';
'ig00';
#
# $Header: rename,v 3.0.1.2 90/08/09 03:17:57 lwall Locked $
#
# $Log:	rename,v $
# Revision 3.0.1.2  90/08/09  03:17:57  lwall
# patch19: added man page for relink and rename
# 

if ($ARGV[0] eq '-i') {
    shift;
    if (open(TTYIN, "</dev/tty") && open(TTYOUT,">/dev/tty")) {
	$inspect++;
	select((select(TTYOUT),$|=1)[0]);
    } 
}
($op = shift) || die "Usage: rename [-i] perlexpr [filenames]\n";
if (!@ARGV) {
    @ARGV = <STDIN>;
    chop(@ARGV);
}
for (@ARGV) {
    unless (-e) {
	print STDERR "$0: $_: $!\n";
	$status = 1;
	next;
    } 
    $was = $_;
    eval $op;
    die $@ if $@;
    if ($was ne $_) {
	if ($inspect && -e) {
	    print TTYOUT "remove $_? ";
	    next unless <TTYIN> =~ /^y/i;
	} 
	unless (rename($was, $_)) {
	    print STDERR "$0: can't rename $was to $_: $!\n";
	    $status = 1;
	}
    } 
}
exit $status;
##############################################################################

	# These next few lines are legal in both Perl and nroff.

.00;			# finish .ig
 
'di			\" finish diversion--previous line must be blank
.nr nl 0-1		\" fake up transition to first page again
.nr % 0			\" start at page 1
';<<'.ex'; #__END__ ############# From here on it's a standard manual page ############
.TH RENAME 1 "July 30, 1990"
.AT 3
.SH NAME
rename \- renames multiple files
.SH SYNOPSIS
.B rename [-i] perlexpr [files]
.SH DESCRIPTION
.I Rename
renames the filenames supplied according to the rule specified as the
first argument.
The argument is a Perl expression which is expected to modify the $_
string in Perl for at least some of the filenames specified.
If a given filename is not modified by the expression, it will not be
renamed.
If no filenames are given on the command line, filenames will be read
via standard input.
.PP
The 
.B \-i
flag will prompt to remove the old file first if it exists.  This
flag will be ignored if there is no tty.
.PP
For example, to rename all files matching *.bak to strip the extension,
you might say
.nf

	rename 's/\e.bak$//' *.bak

.fi
To translate uppercase names to lower, you'd use
.nf

	rename 'y/A-Z/a-z/' *

.fi
To do the same thing but leave Makefiles unharmed:
.nf

	rename 'y/A-Z/a-z/ unless /^Make/' *

.fi
To rename all the *.f files to *.BAD, you'd use
.nf

	rename 's/\e.f$/.BAD/' *.f

.SH ENVIRONMENT
.fi
No environment variables are used.
.SH FILES
.SH AUTHOR
Larry Wall
.SH "SEE ALSO"
mv(1)
.br
perl(1)
.SH DIAGNOSTICS
If you give an invalid Perl expression you'll get a syntax error.
.SH BUGS
.I Rename
does not check for the existence of target filenames, so use with care.
.ex
--
Tom Christiansen		tchrist@convex.com	convex!tchrist
"With a kernel dive, all things are possible, but it sure makes it hard
 to look at yourself in the mirror the next morning."  -me

bobmon@iuvax.cs.indiana.edu (RAMontante) (12/12/90)

Here's some source, gotten from Keith Petersen/Bill Davidsen/Frank da Cruz;
does casing and other neat stuff too.  Originally from comp.binaries.ibm.pc
(I think).

One-liners... HMMMPH!



/*  X X U  --  20-to-Unix filename converter  */

/**
 ** This can be very handy for fixing uppercase case and illegal filenames
 ** on Unix.  Why is it posted here?  Because it's a tool for getting
 ** MSDOS files from comp.binaries.ibm.pc and SIMTEL20.
 ** 
 ** Thanks to Bill Davidsen for the update.
 ** 
 ** Keith Petersen
 ** Maintainer of the CP/M & MSDOS archives at
 **     WSMR-SIMTEL20.ARMY.MIL [26.0.0.74]
 ** DDN: W8SDZ@WSMR-SIMTEL20.ARMY.MIL
 ** Uucp: {ames,decwrl,harvard,rutgers,ucbvax,uunet}
 **     !wsmr-simtel20.army.mil!w8sdz
 **/

/*
 Change DEC-20 or VAX/VMS style filenames into normal Unix names.
 Handy for use after ftp MGETs, when you find your directory full of
 files with names like LIB:<KERMIT>CKUFIO.C.2 or FRED::[ETHEL]A.B;37
 when all you really wanted was ckufio.c and a.b.

 Usage: xxu file(s)

 Action: Renames argument files as follows:
   strips Unix path name from front (up to rightmost '/') if present
   strips DEC device:, node:: names from front (up to rightmost ':') if present
   strips DEC-20 <directory> or VMS [directory] name if present
   strips DEC-20 version number from end (everything after 2nd dot) if present
   strips VMS generation number from end (everything after ';') if present
   lowercases any uppercase letters
   honors DEC-20 CTRL-V quote for special characters
   discards unquoted unprintable characters
   if result is null, file is renamed to xxfile-n, where n is a number.
   if result would write over an existing file, file also renamed to xxfile-n.

 Recommended procedure: make a new directory, cd to it, then FTP files
 from DEC-20 or VMS system, then do "xxu *".

 Author:  F. da Cruz, CUCCA, July 85
*/

#include <stdio.h>
#if	SYSV | M_XENIX
#include <sys/types.h>
#endif
#include <ctype.h>
#include <sys/file.h>			/* For access() */
/* <<<<<<<< define NO_RENAME on cc line if missing >>>>>>>> */

char name[500];				/* File name buffer */
char *pp, *cp, *xp;			/* Character pointers */
char delim;				/* Directory Delimiter */
int dc = 0, n = 0;			/* Counters */
int quote = 0, indir = 0, done = 0;	/* Flags */

int main(argc,argv) int argc; char **argv; {

    if (argc < 2) {			/* Give message if no args */
	fprintf(stderr,"Usage: xxu file(s)\n");
	exit(1);
    }
    n = 0;				/* Unfixable filename counter */
    while (--argc > 0) {		/* For all files on command line... */
	argv++;
	xp = *argv;			/* Copy pointer for simplicity */
	printf("%s ",*argv);		/* Echo name of this file */

	pp = name;			/* Point to translation buffer */
	*name = '\0';			/* Initialize buffer */
	dc = 0;				/* Filename dot counter */
	done = 0;			/* Flag for early completion */

	for (cp = xp; (*cp != '\0') && !done; cp++) { /* Loop thru chars... */

	    if (quote) {		/* If this char quoted, */
		*pp++ = *cp;		/*  include it literally. */
		quote = 0;
	    }
	    else if (indir) {		/* If in directory name, */
		if (*cp == delim) indir = 0; /* look for end delimiter. */
	    }
	    else switch (*cp) {
		case '<':		/* Discard DEC-20 directory name */
		    indir = 1;
		    delim = '>';
		    break;
		case '[':		/* Discard VMS directory name */
		    indir = 1;
		    delim = ']';
		    break;
		case '/':		/* Discard Unix path name */
		case ':':   	    	/*  or DEC dev: or node:: name */
		    pp = name; 
		    break;
		case '.':		/* DEC -20 generation number */
	    	    if (++dc == 1)	/* Keep first dot */
		    	*pp++ = *cp;
		    else		/* Discard everything starting */
		    	done = 1;	/* with second dot. */
		    break;
		case ';':		/* VMS generation or DEC-20 attrib */
		    done = 1;		/* Discard everything starting with */
		    break;		/* semicolon */
	    	case '\026':		/* Control-V quote for special chars */
		    quote = 1;		/* Set flag for next time. */
		    break;
		default:
		    if (isupper(*cp))  	/* Uppercase letter to lowercase */
	    	    	*pp++ = tolower(*cp);
		    else if (*cp == ' ')/* change blanks to underscore */
		        *pp++ = '_';
		    else if (isprint(*cp)) /* Other printable, just keep */
		    	*pp++ = *cp;
	    }
	}
	*pp = '\0';			/* Done with name, terminate it */
	if (strcmp(name,xp) == 0) {	/* If no renaming necessary, */
	    printf("(ok)\n");		/*  just give message. */
	    continue;
        }
	while (*name == '\0' || access(name,0) == 0) { /* Find unique name */
	    sprintf(name,"xxfile-%d",n++);
	}
	printf("=> %s ",name);		/* Tell what new name will be */
	if (rename(xp,name) == 0)	/* Try to rename it */
	    printf("(ok)\n");		/* Say what happened */
	else
	    perror("failed");
    }
    return 0;				/* Done. */
}

/*****************************************************************
 |  rename - for systems lacking the rename system call
 |----------------------------------------------------------------
 |  Arguments:
 |   1) string - current filename
 |   2) string - new filename
 ****************************************************************/

#if	NO_RENAME
rename(oldname, newname)
    char *oldname, *newname;
{
    char cmdline[133];
    
    sprintf(cmdline, "mv \"%s\" %s", oldname, newname);
    return system(cmdline);
}
#endif

dupuy@cs.columbia.edu (Alexander Dupuy) (12/12/90)

Well, I didn't write this, and if I did it now, I'd do it in perl, but it's
pretty cute, since it not only downcases files, it will strip directory names
and Twenex/VMS extensions and attributes.

: This is a shar archive.  Extract with sh, not csh.
: The rest of this file will extract: 
:
:	xxu.c
:
echo x - xxu.c
sed 's/^X//' > xxu.c << '//go.sysin dd *'
X/*  X X U  --  20-to-Unix filename converter  */
X
X/*
X Change DEC-20 or VAX/VMS style filenames into normal Unix names.
X Handy for use after ftp MGETs, when you find your directory full of
X files with names like LIB:<KERMIT>CKUFIO.C.2 or FRED::[ETHEL]A.B;37
X when all you really wanted was ckufio.c and a.b.
X
X Usage: xxu file(s)
X
X Action: Renames argument files as follows:
X   strips Unix path name from front (up to rightmost '/') if present
X   strips DEC device:, node:: names from front (up to rightmost ':') if present
X   strips DEC-20 <directory> or VMS [directory] name if present
X   strips DEC-20 version number from end (everything after 2nd dot) if present
X   strips VMS generation number from end (everything after ';') if present
X   lowercases any uppercase letters
X   honors DEC-20 CTRL-V quote for special characters
X   discards unquoted unprintable characters
X   if result is null, file is renamed to xxfile-n, where n is a number.
X   if result would write over an existing file, file also renamed to xxfile-n.
X
X Recommended procedure: make a new directory, cd to it, then FTP files
X from DEC-20 or VMS system, then do "xxu *".
X
X Author:  F. da Cruz, CUCCA, July 85
X*/
X#include <stdio.h>
X#include <ctype.h>
X#include <sys/file.h>			/* For access() */
X
Xchar name[500];				/* File name buffer */
Xchar *pp, *cp, *xp;			/* Character pointers */
Xchar delim;				/* Directory Delimiter */
Xint dc = 0, n = 0;			/* Counters */
Xint quote = 0, indir = 0; done = 0;	/* Flags */
X
Xmain(argc,argv) int argc; char **argv; {
X
X    if (argc < 2) {			/* Give message if no args */
X	fprintf(stderr,"Usage: xxu file(s)\n");
X	exit(1);
X    }
X    n = 0;				/* Unfixable filename counter */
X    while (--argc > 0) {		/* For all files on command line... */
X	argv++;
X	xp = *argv;			/* Copy pointer for simplicity */
X	printf("%s ",*argv);		/* Echo name of this file */
X
X	pp = name;			/* Point to translation buffer */
X	*name = '\0';			/* Initialize buffer */
X	dc = 0;				/* Filename dot counter */
X	done = 0;			/* Flag for early completion */
X
X	for (cp = xp; (*cp != '\0') && !done; cp++) { /* Loop thru chars... */
X
X	    if (quote) {		/* If this char quoted, */
X		*pp++ = *cp;		/*  include it literally. */
X		quote = 0;
X	    }
X	    else if (indir) {		/* If in directory name, */
X		if (*cp == delim) indir = 0; /* look for end delimiter. */
X	    }
X	    else switch (*cp) {
X		case '<':		/* Discard DEC-20 directory name */
X		    indir = 1;
X		    delim = '>';
X		    break;
X		case '[':		/* Discard VMS directory name */
X		    indir = 1;
X		    delim = ']';
X		    break;
X		case '/':		/* Discard Unix path name */
X		case '\\':		/*  or messy-dos path name */
X		case ':':   	    	/*  or DEC dev: or node:: name */
X		    pp = name; 
X		    break;
X		case '.':		/* DEC -20 generation number */
X	    	    if (++dc == 1 && cp[1] != '.' && cp[1] != '\0')
X		    	*pp++ = *cp;	/* Keep first dot if nonempty .ext */
X		    else		/* Discard everything starting */
X		    	done = 1;	/* with second dot. */
X		    break;
X		case ';':		/* VMS generation or DEC-20 attrib */
X		    done = 1;		/* Discard everything starting with */
X		    break;		/* semicolon */
X	    	case '\026':		/* Control-V quote for special chars */
X		    quote = 1;		/* Set flag for next time. */
X		    break;
X		default:
X		    if (isupper(*cp))  	/* Uppercase letter to lowercase */
X	    	    	*pp++ = tolower(*cp);
X		    else if (isprint(*cp)) /* Other printable, just keep */
X		    	*pp++ = *cp;
X	    }
X	}
X	*pp = '\0';			/* Done with name, terminate it */
X	if (strcmp(name,xp) == 0) {	/* If no renaming necessary, */
X	    printf("(ok)\n");		/*  just give message. */
X	    continue;
X        }
X	while (*name == '\0' || access(name,0) == 0) { /* Find unique name */
X	    sprintf(name,"xxfile-%d",n++);
X	}
X	printf("=> %s ",name);		/* Tell what new name will be */
X	if (rename(xp,name) == 0)	/* Try to rename it */
X	    printf("(ok)\n");		/* Say what happened */
X	else
X	    perror("failed");
X    }
X    exit(0);				/* Done. */
X}
//go.sysin dd *
exit
--
-- 
inet: dupuy@cs.columbia.edu
uucp: ...!rutgers!cs.columbia.edu!dupuy

jrr@nsc.nsc.com (Jerry Roe) (12/14/90)

In article <1990Dec11.150025.2119@mdivax1.uucp> mdivax1!bb29c!mitchell (Bill Mitchell) writes:
>>
>> (shell script deleted)
>
>Yours is similar to the one I was using, until I saw this one posted:
>
>for file in $*
>do
>	mv -i $file `echo $file | tr A-Z a-z`
>done
>
>The mv program typically refuses to overwrite an existing file and, having
                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>failed, leaves the original file in place with its original name.


Uh, it's implicit in your script because of the "-i" option to mv, but some
newer Unix users might miss that and instead focus on the "typically refuses
to overwrite" part of your comment.  mv, of course, typically *gladly* over-
writes an existing file if used without the -i option.

Yeah, I know - this is a source group, not discussion, so sorry for the
non-source posting, but I thought some poor novice might benefit.


Jerry Roe
National Semiconductor
Santa Clara, CA