mvredir
a unix shell command-line program
Move a web page and leave behind a redirect page to the new location. See also mkredir
.
A redirect page allows a browser to get to a page at a new location even though the browser was told to get the page at the obsolete location. It is always a good idea to leave behind a redirect page at the old location when you move a page, so that links to the old location still work. This approach is preferable to a unix symbolic link (symlink) or “hard link” because those approaches proliferate different locations for the same page. Also, if the page moves to a different position in the hierarchy, relative links will not work when the page is accessed from a different path.
Examples:
1 Z% mvredir oldname.html newname.html 2 Z% mvredir *.html newdir1.
oldname.html
will redirect tonewname.html
2.
name1.html
will redirect tonewdir/name1.html
;olddir/name1.html
will redirect to../newdir/name1.html
, etc.
The usage summary is this:
Usage:
mvredir [ -f ] [ -b ] old new
mvredir [ -f ] [ -b ] old ... directoryMove
old
tonew
, then createold
containing HTML redirecting tonew
.
The-f
option forces replacement of the target if it already exists.
The-b
option causes the redirect file(s) to have a<body>
that says:
One moment while we redirect you to the page.
Theold
argument(s) must all be in the current directory.
This works only for redirecting html files.
If you want to redirect a directory, you have to use the Apache RedirectPermanent
directive
(see the Apache Alias module (mod_alias) documentation).
For example, I redirect from http://Yost.com/yostupload to its real location in a .htaccess
file, like this:
RedirectPermanent /yostupload http://Yost.com/computers/yostupload
The presence of a <body>
in the redirect page makes the redirect take longer and is necessary only for extremely old browsers.
Here’s the mvredir
program:
#!/bin/zsh # See notice of copyright and license at end. commandName=${0##*/} main() { doArgs "$@" umask og+rx if [[ $# == 2 && ! -d "$2" ]] ; then if ! move "$1" "$2" ; then exit 2 fi else args=("$@") dir="$args[$#]" args[-1]=() for file in "${args[@]}" do if ! move "$file" "$dir/${file##*/}" ; then exit 2 fi done fi } #------------------------------------------------------------------------------- usage() { if [[ $1 != '' ]] ; then echo 1>&2 "\n$1" ; fi echo 1>&2 " Usage: $commandName [ -f ] [ -b ] old new or $commandName [ -f ] [ -b ] file ... directory Move old to new, then create old containing HTML redirecting to new. The -f option forces replacement of the target if it already exists. The -b option causes the redirect file(s) to have a <body> that says: One moment while we redirect you to the page This version requires moving from the current directory, and the destination must be a relative path. " exit 2 } doArgs() { argForce=() argBody=() zparseopts -D -K - -help=argHelp f=argForce b=argBody case "$1" in -*) usage "Unknown option: $1" ;; esac case $# in 0|1|) usage ;; 2) ;; *) if [[ ! -d "$*[-1]" ]] ; then usage "$*[-1]: not a directory" fi ;; esac if [[ $#argHelp != 0 ]] ; then usage fi } entitize() { echo '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html><head><title></title></head><body><a href="'"$1"'">x</a></body></html>' \ | tidy -q 2> /dev/null \ | sed -n ' s,">x.*,, s,.*href=",,p ' return 0 } filter() { target=$(entitize "$1") sedArgs='s,^ ,,' if [[ $#argBody != 0 ]] ; then sedArgs="$sedArgs /<!-- /d / -->/d " fi targetEscaped=$(echo "$target" | sed 's,|,\\|,') sedArgs="$sedArgs s|__PLACEHOLDER__|$targetEscaped| " sed "$sedArgs" return 0 } makeRedirectPage() { redirect="$1" destination="$2" if [[ -e "$destination" ]] ; then if [[ $#argForce == 0 ]] ; then echo 1>&2 "$commandName: ${destination}: File exists" return 2 else rm -f "$destination" fi fi echo '<?xml version="1.0" encoding="iso-8859-1"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="content-type" content="text/html;charset=iso-8859-1" /> <meta http-equiv="Refresh" content="0; URL=__PLACEHOLDER__" /> <meta http-equiv="Expires" content="Tue, 1 Jan 1997 0:0:0 GMT" /> <title>Redirect</title> </head> <!-- <body bgcolor="#ffffff"> <h3 align="center"> <br />One moment while we redirect you to <a href="__PLACEHOLDER__">the page</a>.</h3> </body> --> </html> ' \ | filter "$redirect" \ > "$destination" return $? } relativePath() { source="$1" destin="$2" # Output a relative path from source to dest. # Assume cwd is a/b/c/ # relativePath ../f1 dir/f2 # -> c/dir/f2 # relativePath ../dir1/f1 dir2/f2 # -> ../c/dir2/f2 # relativePath dir2/f1 ../f2 # -> ../../f2 # relativePath dir/f1 ../dir/f2 # -> ../../dir/f2 # relativePath ../dir1/f1 ../dir2/f2 # equivalent to dir1/f1 dir2/f2 # relativePath dir1/f1 dir2/f2 # -> ../dir2/f2 # Also must handle full path cases # This needs a lot more work. Too much punting. sourceDirPart=${source%/*} destinDirPart=${destin%/*} case "$destinDirPart" in '' | /*) echo 1>&2 "$commandName: In this version you can't use full paths." return 2 ;; esac case "$sourceDirPart" in '' | /*) echo 1>&2 "$commandName: In this version you can't use full paths." return 2 ;; "$source") echo "$destin" ;; *) echo 1>&2 "$commandName: In this version you can move from the current directory only." return 2 ;; esac return 0 } move() { old="$1" new="$2" if ! redirectPath="$(relativePath "$old" "$new")" ; then return 2 fi if [[ -e "$new" ]] ; then if [[ $#argForce == 0 ]] ; then echo 1>&2 "$commandName: ${new}: File exists" return 2 else rm -f "$new" fi fi /bin/mv $argForce "$old" "$new" makeRedirectPage "$redirectPath" "$old" return $? } TRAPINT() { echo 1>&2 "$commandName aborting: interrupted at file $file" exit 2 } #------------------------------------------------------------------------------- main "$@" # Copyright 2005 Dave Yost <Dave@Yost.com> # All rights reserved. # This version is # mvredir 1.1 2006-07-20 # which at time of this publication can be found at: # http://Yost.com/computers/mvredir # Redistribution and use in the form of source code or derivative data built # from the source code, with or without modification, are permitted provided # that the following conditions are met: # 1. THE USER AGREES THAT THERE IS NO WARRANTY. # 2. If and only if appropriate, the above phrase "This version is" must be # followed by the phrase "a modified form of" or "extracted from" or # "extracted and modified from". # 3. Redistributions of source code must retain this notice intact. # 4. Redistributions in the form of derivative data built from the source # code must reproduce this notice intact in the documentation and/or other # materials provided with the distribution, and each file in the derivative # data must reproduce any Yost.com URI included in the original distribution. # 5. Neither the name of Dave Yost nor the names of its contributors may be # used to endorse or promote products derived from this software without # specific prior written permission. # 6. Written permission by the author is required for redistribution as part # of a commercial product. # This notice comprises all text from "Copyright" above through the end of # this sentence.