#!/bin/sh
me=$(basename $0)
usage() {
err=$1; out=2
[ $err -eq 0 ] && out=1
printf "\
$me [OPTION] 'FILTER' FILE...
Replace the contents of each FILE after processing with FILTER
--backup[=CONTROL] make a backup of each existing destination file
-b like --backup but does not accept an argument
-C, --compare compare each pair of source and destination files, and
in some cases, do not modify the destination at all.
-p, --preserve-timestamps apply access/modification times of SOURCE files
to corresponding destination files.
-S, --suffix=SUFFIX override the usual backup suffix
The backup suffix is \`~', unless set with --suffix or SIMPLE_BACKUP_SUFFIX.
The version control method may be selected via the --backup option or through
the VERSION_CONTROL environment variable. Here are the values:
none never make backups (even if --backup is given)
numbered make numbered backups
existing numbered if numbered backups exist, simple otherwise
simple always make simple backups
Report "$me" bugs to address@hidden
GNU coreutils home page:
General help using GNU software:
Report "$me" translation bugs to
" >&$out
exit $err
}
version() {
Cmd=$1; Date=2010; Version=8.5 #TODO: auto update
#TODO: translation
printf "\
$Cmd (GNU coreutils) $Version
Copyright (C) $Date Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later .
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Written by Pádraig Brady.
"
exit 0
}
if getopt -T >/dev/null 2>&1; test $? -ne 4; then
# Enhanced getopt(1) not available and POSIX getopts
# only supports short options, so revert to simple manual parsing
if test $# -lt 2; then
test "$1" = "--help" && usage 0
test "$1" = "--version" && version "$me"
usage 1
fi
else
OPT=$(
getopt -o bCpS: \
--long backup::,compare,help,preserve-timestamps,suffix:,version \
-n"$me" -- "$@" ||
usage 1
)
eval set -- "$OPT"
while true; do
case "$1" in
-b)
test "$VERSION_CONTROL" || VERSION_CONTROL="existing"
backup="$VERSION_CONTROL"; shift;;
--backup)
case "$2" in
"") backup=existing; shift 2;;
*) backup="$2"; shift 2;;
esac;;
-C|--compare) compare=1; shift;;
-p|--preserve-timestamps) preserve_times=1; shift;;
-S|--suffix) suffix="$2"; shift 2;;
--help) usage 0; shift;;
--version) version "$me"; shift;;
--) shift; break ;;
*) echo "Option processing error"; exit 1;;
esac
done
if test "$backup"; then
backup="--backup=$backup"
test "$suffix" && backup="$backup --suffix=$suffix"
fi
if test $# -lt 1; then
printf "\
$me: missing file operand
Try \`$me --help' for more information.
"
fi
fi
filter="$1"; shift
cleanup() { rm -f "$tf"; }
trap "cleanup" EXIT
filter_file() {
ret=0
if $filter < "$file" > "$tf"; then
if test "$preserve_times"; then
touch "$tf" --reference="$file" || { ret=1; fail=1; }
fi
else
ret=1; fail=1
fi
if test $ret = 0; then
if test "$compare"; then
cmp -s -- "$tf" "$file"
status=$?
test $status -eq 0 && { ret=1; } # Don't process further
test $status -gt 1 && { ret=1; fail=1; }
fi
fi
return $ret
}
fail=0
for file in "$@"; do
dir=$(dirname -- "$file")
tf=$(mktemp -q --tmpdir="$dir")
if test -e "$tf" && cp --attr -- "$file" "$tf" 2>/dev/null; then
# Modify file atomically.
# We could `chmod u+rw` here to allow updating non rw files?
filter_file &&
{ mv $backup -- "$tf" "$file" || fail=1; } # rename
else
# cp doesn't support --attributes-only or
# $dir is not writeable. In this case we
# use $TMPDIR, but don't use mv to unlink/copy
# as $TMPDIR might not support all attrs of $dir.
# Also we can't unlink in unwriteable dir.
# Note we won't be able to update non rw files like this.
cleanup # dir/file.tmp
tf=$(mktemp)
filter_file &&
{ cp $backup -- "$tf" "$file" || fail=1; } # truncate and copy
test "$preserve_times" && touch "$file" --reference="$tf"
cleanup # tmp/file.tmp
fi
done
exit $fail