#!/bin/sh set -eu usage() { cat <<-'EOF' Usage: ifnew [-v] FILE ifnew -h EOF } help() { cat <<-'EOF' Options: -v notify when new -h, --help show this message FILE the target to compared against Compare STDIN to FILE, and only write to FILE if STDIN content differs from FILE content. When -v is given, notify on STDERR that FILE has new content (useful for debugging purposes). Examples: Create a new file, don't update it afterwards, and update it as the content changes: $ echo aaa | ifnew new-file $ stat --print='%y' new-file # timestamp 1 $ echo aaa | ifnew new-file $ stat --print='%y' new-file # timestamp 1 $ echo bbb | ifnew new-file $ stat --print='%y' new-file # timestamp 2 Only change file when content changes in a Makefile, and print to STDERR when it does: i18.cfg: ALWAYS gen-cfg | ifnew -v $@ po4a $@ EOF } for flag in "$@"; do case "$flag" in (--) break ;; (--help) usage help exit ;; (*) ;; esac done VERBOSE=false while getopts 'vh' flag; do case "$flag" in (v) VERBOSE=true ;; (h) usage help exit ;; (*) usage >&2 exit 2 ;; esac done shift $((OPTIND - 1)) FILE="${1:-}" eval "$(assert-arg -- "$FILE" 'FILE')" STDIN="$FILE.$(uuid).tmp" trap 'rm -f "$STDIN"' EXIT cat - > "$STDIN" if ! cmp -s "$STDIN" "$FILE"; then MV_ARGS='' if [ "$VERBOSE" = true ]; then printf 'ifnew: "%s" will be updated.\n' "$FILE" >&2 MV_ARGS='-v' fi mv $MV_ARGS "$STDIN" "$FILE" else if [ "$VERBOSE" = true ]; then printf 'ifnew: "%s" left unchanged.\n' "$FILE" >&2 rm -vf "$STDIN" fi fi