#!/bin/bash ## rename -- script to do systematic renaming of files -- by Eugene Reimer 1998-Feb; ## this is an enhanced replacement for the command included in most Linux distributions ## (as part of util-linux package) since circa 1999, although mine predates theirs; ## many commandlines valid with that will do the same thing with this one, ## but not all, because this one replaces ALL occurances, rather than just the first one; ## (this one has many other features, that are extensions rather than changes); ## ## PREREQ: webmv chg fullnameNOSLASH -- from http://ereimer.net/programs/ertools.zip ## NOTE: only with the --web option does this script have those PREREQS; those prereqs were troublesome because my webmv is not "general-purpose", however after ## publishing webmaster-tools, webmv is no longer alone in that regard... ## ## Copyright © 1998,2009 Eugene Reimer; can be used, modified, copied, and distributed or sold under the terms of either the LGPL or the GPL (your choice); ## see http://www.gnu.org/licenses for the details of these terms. AT="$@" while [ $# -gt 0 ] && [[ $1 == -* ]]; do ##parse the options case "$1" in --sed) CMD="sed" ;; --date|-d) CMD="date"; DATE=1 ;; --datepix) CMD="date"; DATEPIX=1 ;; ##2008aug25: added --web|-w) WEB=1 ;; --help|-\?) CMD="help"; HELP=0 ;; --keep*|-k) WEBARG="$WEBARG -k" ;; --nob*|-n) WEBARG="$WEBARG -n" ;; --nos*|-S) WEBARG="$WEBARG -S" ;; ##2010-11: added, --nosource passed to webmv --nor*|-R) WEBARG="$WEBARG -R" ;; ##2010-11: added, --noredirect passed to webmv --tmp*) WEBARG="$WEBARG --tmp" ;; --q*|-q) WEBARG="$WEBARG -q" ;; --test|-t) TEST=1; PROMPT=; WEBARG="$WEBARG -t" ;; --p*|-p) PROMPT=1; TEST=; WEBARG="$WEBARG -p" ;; --f*|-f) FORCE=1 ;; ##2009-11: to suppress newname-exists prompt --v*|-v) VERS=1 ;; --) shift; break ;; *) echo "unknown option: $1"; HELP=2 ;; esac shift; ##remove that arg done [ $VERS ] && echo "rename version:$(date -r$0 +%Y%m%d). Copyright 1998,2008 Eugene Reimer. Use is subject to GPL" && exit 0 if [ "$CMD" = "" ];then ##expect X Y positionals if [ $# -lt 2 ];then HELP=2; else CMD="sed"; ARG="s|$1|$2|g"; shift;shift; fi elif [ "$CMD" = "sed" ];then ##expect sedScript positional if [ $# -lt 1 ];then HELP=2; else ARG="$1"; shift; fi elif [ "$CMD" = "date" ];then ##no positionals for --date / --datepix cmd="sed"; ARG="s|^\([^-.]*\)|\1-YYYYMMDD|" ##do nothing (actual "ARG" will be re-computed for each file) fi [ $TEST ] && echo "##rename: $AT" ##echo "##rename: CMD=$CMD; ARG=$ARG; HELP=$HELP; PROMPT=$PROMPT; TEST=$TEST; WEB=$WEB WEBARG=$WEBARG;" ##DEBUG if [ $HELP ]; then echo "usage: rename options 'X' 'Y' [file]..." echo " or: rename options --sed sedScript [file]..." echo " or: rename options --date [file]..." ##ho " or: rename options --datepix [file]..." echo "The 1st form revises filenames with sed s|X|Y|g;" echo "the 2nd form revises filenames with sed using the supplied sedScript;" echo "the 3rd form revises filenames with sed s|^\([^-.]*\)|\1-YYYYMMDD| using the file's modification-timestamp;" ##ho "the 4th form revises filenames with sed s|_.*_|_|; s|_|_YYYYMMDD_| using the file's EXIF-timestamp." echo " --web | -w for each renamed file, also revise references in HTML files to that file;" echo " the use of --web has further implications, as explained below" echo " --test | -t just show mv-commands that would be done, but do not change anything;" echo " tip: the output may be redirected into a file, edited, then executed" echo " --prompt | -p ask user for each matching filename before doing the rename;" echo " and during --web revising, show diff's and prompt before revising" echo " --force | -f do the renaming even when newname exists" echo " --keeptimestamp | -k during --web revising, revised file keeps previous modification-timestamp" echo " --nobackup | -n during --web revising, no copy kept of previous file contents" echo " --tmpbackup during --web revising, backup under /tmp, instead of in current directory" echo " --quiet | -q during --web revising, suppress messages about file modification and backup" echo " --help | -? just show this info on usage" echo " --version | -v just show version info" echo "If no files specified, then all matching filenames in current directory are revised." echo "Using --web results in renames being done with rather than ; see ." echo "Examples:" echo " rename ' ' '' # revise all filenames in current directory, removing all spaces" echo " rename --sed 's| ||g' # exactly the same as preceding line" echo " rename --web '^-' 'img-' # revise filenames having a leading hyphen (e.g. wvHtml output)" echo " rename --test --date Ch*htm >tmp # write date-adding mv-commands to file tmp" echo " rename --test Ch Ch Ch*htm >tmp # write do-nothing mv-commands, for selected files, to file tmp" exit $HELP; ##exit fi [ $# -eq 0 ] && set ..?* .[^.]* *; ##match all files -- this is the default if no files specified! ##set -xv MV="mv"; MVARG="-b"; ##2005may: changed from -f to -b [ $WEB ] && MV="webmv" && MVARG="$WEBARG -f" ##2005sep: added -f when using webmv (it doesn't support -b) for f in "$@";do [ -e "$f" ] || continue ##because nullglob is broken if [ $DATE ];then sedarg="s|^\([^-.]*\)|\1-$(date -r"$f" +%Y%m%d)|" ##add -YYYYMMDD before first hyphen/dot, if any (2008aug25: %y-->%Y) elif [ $DATEPIX ];then sedarg="s|_.*_|_|; s|_|_$(dateEXIF-ERW "$f" +%Y%m%d)_|" ##add _YYYYMMDD before last underscore, replacing... (2008aug25) else sedarg="$ARG" ##use ARG which is from the X Y or sedScript positionals fi NEWNAME=$(echo "$f" |sed "$sedarg") ##form newname using sed (2005may: simplified) if [ $TEST ];then echo "$MV $MVARG -- \"$f\" \"$NEWNAME\""; continue; fi ##for -t, produce mv-cmd to stdout & continue; 201007:was after REM= line [ "$NEWNAME" = "$f" ] && continue ##filename-unchanged => skip it; was: non-matching filename REM=; [ -e "$NEWNAME" ] && REM="##--NEWNAME-EXISTS--" ##05may: test whether newname exists if [ $PROMPT ] || [[ $REM != "" && $FORCE == "" ]];then ##2009-11: FORCE overrides newname-exists prompt if [ $PROMPT ];then echo -n "##apply $MV $MVARG -- \"$f\" \"$NEWNAME\" $REM -- Y/N?" >&2 ##ask user, showing mv-cmd + existing-newname-info elif [ "$REM" ];then echo -n "##newname:$NEWNAME exists -- rename anyway Y/N?" >&2 ##ask user, only because newname exists fi read; [[ $REPLY == [Nn]* ]] && continue ##skip if user says NO fi $MV $MVARG -- "$f" "$NEWNAME" ##execute the mv-cmd done exit 2005-May: major revision, combining all of my [web][re]name[sed] scripts, plus my namedate; 2006-June: considered -y option to avoid the "also on sdb6" prompting => modify both mv and webmv; instead, modified mv+webmv to remove that prompt; 2008-Aug: now do -p prompting for each file; eliminated the 2-pass nature; will now correctly handle those cases where an earlier rename ought to result in a later one having the newname-exists condition... 2008-Aug: added --datepix mode, to rename using the file's EXIF-date, adding _DATETIME before _PHOTOG (to comply with my image-naming conventions); see also: copy+rename-for-chronological-ordering -- as used for Inuvik-Trip slideshow; 2009-11: added -f option to avoid prompts for "newname exists", for scripts such as tesseract-training-steps!! 2010-06: -f (FORCE) appears not to work; still getting prompt "##newname:$NEWNAME exists -- rename anyway Y/N?" was on a complex case: an image-rename from mbox-cleanup calls tohtm calls doc2htm... 2010-07: revised the non-matching-filename test, making it a filename-unchanged test -- to behave sensibly on --sed with multiple s-cmds; was: NEWNAME=$(echo "$f" |sed -n "${sedarg}p"); [ "$NEWNAME" = "" ] && continue note: using -n and adding "p" to each s-cmd won't do what's needed; need to separate "matching" from revising; sadly revised test will mean losing the simple way of making list of no-op mv-cmds to be edited; consider new option to do that, or revising --test semantics?? solved by producing --test output whether or not filename changes; ie: moving the "if [ $TEST..." line ahead of the "skip if name unchanged" line;