#!/bin/sh usage () { cat <&2 Usage: ${0##*/} [OPTIONS] SEARCH REPLACE [FILES] Replace SEARCH by REPLACE in FILES. If no file is provided, use stdin. Backslashes are interpreted in SEARCH and REPLACE (e.g. \n, \t). If you want to inhibit this behaviour, you need to double them. Options: -h: Show this help. -i: Replace file content instead of printing to stdout. EOF } OPT_INPLACE="" while getopts ":ih" opt; do case $opt in i) OPT_INPLACE=-i ;; h) usage exit 1 ;; \?) usage exit 1 ;; esac done shift $((OPTIND - 1)) if [ $# -lt 2 ]; then usage exit 1 fi search="$1" replace="$2" shift 2 replace () { ## We cannot use gsub, otherwise regex substitutions could occur. ## Source: http://mywiki.wooledge.org/BashFAQ/021 awk -v s="$search" -v r="$replace" 'BEGIN {l=length(s)} {o="";while (i=index($0, s)) {o=o substr($0,1,i-1) r; $0=substr($0,i+l)} print o $0}' "$@" } if [ $# -eq 0 ] || [ -z "$OPT_INPLACE" ]; then replace "$@" else for i ; do out="$(mktemp "$i.XXXXXX")" replace "$i" > "$out" mv "$out" "$i" done fi