From owner-freebsd-questions@FreeBSD.ORG Mon Oct 6 22:23:25 2003 Return-Path: Delivered-To: freebsd-questions@freebsd.org Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id 2113216A4BF for ; Mon, 6 Oct 2003 22:23:25 -0700 (PDT) Received: from enmu.edu (EM01.enmu.edu [192.94.216.103]) by mx1.FreeBSD.org (Postfix) with ESMTP id 06C9943FF9 for ; Mon, 6 Oct 2003 22:23:24 -0700 (PDT) (envelope-from groups@xscd.com) Received: from TSEH045.enmu.edu (TSEH045.enmu.edu [198.59.107.143]) by enmu.edu (Postfix) with ESMTP id 22206BC18C for ; Mon, 6 Oct 2003 23:23:17 -0600 (MDT) From: steve To: questions@freebsd.org Date: Mon, 6 Oct 2003 23:23:26 -0600 User-Agent: KMail/1.5.2 MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Content-Disposition: inline Message-Id: <200310062323.26081.groups@xscd.com> Subject: Shell script--batch rename files X-BeenThere: freebsd-questions@freebsd.org X-Mailman-Version: 2.1.1 Precedence: list List-Id: User questions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 07 Oct 2003 05:23:25 -0000 Hello All-- I'm a novice shell programmer, but I thought I would begin to learn by writing a script that had a need for but could not find an equivalent of on the Internet. I decided to post it here (a) in case anyone else might find it useful and (b) to expose it to more experienced script authors who might be kind enough to offer helpful criticisms or suggestions. (the script appears in its entirety at the end of this email) I wrote the script (it works with /bin/sh or BASH) to address the following problem-- I have many folders of image files (from my digital camera, received as email attachments or downloaded from the Internet) that I have sorted into folders by theme (such as "friends," "family," "vacation_2003," etc.), and many of them have filenames I would like to change on a per-directory basis, either because they are too generic (IMG_0105.JPG, IMG_0106.JPG, etc.), or because the filenames have spaces or unusual characters within them, or simply to make all the filenames in each directory have the same root name with a unique numerical index appended, maintaining their original filename extension (or adding one, if desired). The script works on files in the shell's current directory only (and not on any subdirectories within), and renames every file (but not subdirectories or symbolic links) using a user-specified name followed by a numerical index, followed by the file's original filename extension (if there was any). On my machine I have titled the script mvb (like a "batch" version of mv), and it seems to work well so far during the couple months I have been working on it. Like I said, I post it here in case anyone else may find it useful and to learn from any criticisms, comments and suggestions it might generate. Thank you, Steve -------CUT-HERE----shell-script-begins-on-next-line------- #!/bin/sh #---------------------------------------------------- # Change the path above to point to the location on # your computer of either the Bourne shell (sh) or # the BASH (Bourne Again) shell (bash). # # This shell script was written to "batch rename" files # (change the name of many files at once) in the # current working directory. # # For his personal use the author named this script # mvb (MV-Batch) in reference to the mv command # of *nix/Linux (which this script uses). # # Written by: Steve Doonan, Portales, NM US # Email: xscd@xscd.com # Date: October, 2003 #---------------------------------------------------- if [ $# -eq 0 ] then cat << _EOF_ -------------------------------------------------- You did not specify a NEWNAME for the files. After the name of the command please enter a SPACE followed by the name you would like all the files in the current directory to be renamed to. -------------------------------------------------- _EOF_ exit fi NEWNAME="$(echo "$1" | tr -Cs '[:alnum:]' '_')" cat << _EOF_ ------------------------------------------------------- Rename files to--> $NEWNAME Current directory--> $(pwd) Continue? (Press RETURN or ENTER) TO QUIT, type q (then press RETURN or ENTER) FOR INFORMATION, type i (then press RETURN or ENTER) ------------------------------------------------------- _EOF_ read CONTINUE case $CONTINUE in [!i]* ) exit ;; i ) cat << _EOF_ ---------------------------------------------------------------- INFORMATION This shell script (Bourne or BASH) will RENAME all visible files (files that don't begin with a dot) in the current directory, to a name you specify, appending a numerical index to each filename so that each is unique, and retaining the original filename extension, if one exists. This script will NOT rename subdirectories or symbolic links contained within the current directory, nor will it descend into subdirectories to rename files within them. If the script does not see what looks like an existing valid FILENAME EXTENSION (3-4 characters following a dot at the end of a filename), it will ask for one. If you WANT to add a filename extension, just type 3 or 4 characters (i.e. jpg, txt, html), with or without a preceding dot--the script will provide the dot if you do not. If you do NOT want the filename to have an extension, just press RETURN or ENTER at that prompt without typing any characters, and no filename extension will be added. To QUIT this program at any time, press CONTROL-C To CONTINUE, press RETURN or ENTER ---------------------------------------------------------------- _EOF_ read CONTINUE ;; esac INDEX=0 make_zero-padded_index_number () { INDEX=$(($INDEX + 1)) INDEX_COUNT="$(echo "$INDEX" | wc -c)" PADDING_ZEROS="$(ls "$(pwd)" | wc -l | tr '[:digit:]' '0' | tr -d '[:space:]')" INDEX_ALPHANUMERIC="$(echo "${PADDING_ZEROS}${INDEX}" | cut -c$INDEX_COUNT-)" } for I in * do #----------------------------------------- # if file is NOT a directory or a link... #----------------------------------------- if [ -f "$I" -a ! -L "$I" ] then #----------------------------------------------- # if filename has a 3 or 4 character extension... #----------------------------------------------- if echo "$I" | grep "\.[^.0-9]\{3,4\}$" > /dev/null then #------------------------------------------------ # assign filename extension to variable EXTENSION #------------------------------------------------ EXTENSION="$(echo "$I" | sed 's/^.*\(\.[^.]*\)$/\1/')" #----------------------------------------------------- # otherwise, ask for a filename extension (or none)... #----------------------------------------------------- else echo "" echo '------------------------------------------------------------' echo "FILENAME: $I" echo "No (or improbable) filename extension found" echo "Enter new filename extension, or press RETURN or ENTER" echo -n "for no filename extension: " read NEW_EXTENSION #----------------------------------------------------------------- # cut the new extension (if any) down to no more than 4 characters #----------------------------------------------------------------- NEW_EXTENSION="$(echo "$NEW_EXTENSION" | sed 's/^\.*\(.\{0,4\}\).*$/\1/'| tr -C '[:alnum:]\12' '_' )" echo '------------------------------------------------------------' echo "" if [ -n "$NEW_EXTENSION" ] then EXTENSION=".${NEW_EXTENSION}" else EXTENSION='' fi fi #---------------------------------------------------------------------- # at this point, EXTENSION should be set correctly--an alphanumeric # index number is created (by the function make_zero-padded_index_number) # and the file is renamed (with a slightly different name if the computed # filename already exists in the current directory). #---------------------------------------------------------------------- make_zero-padded_index_number RENAME_TO="${NEWNAME}${INDEX_ALPHANUMERIC}${EXTENSION}" if [ -e "$RENAME_TO" ] then RENAME_TO="${NEWNAME}${INDEX_ALPHANUMERIC}a${EXTENSION}" fi chmod 664 "$I" mv -iv -- "$I" "$RENAME_TO" fi done cat << _EOF_ --------------------------------------------------- The files have been renamed. Script exiting... --------------------------------------------------- _EOF_