1#! /module/for/moderni/sh 2\command unalias replacein 2>/dev/null 3 4# var/string/replacein 5# 6# replacein: Replace the leading or (-t)railing occurrence or (-a)ll 7# occurrences of a string by another string in a variable. 8# 9# Usage: replacein [ -t | -a ] <varname> <oldstring> <newstring> 10# 11# TODO: support glob 12# TODO: reconsider option letters 13# 14# --- begin license --- 15# Copyright (c) 2019 Martijn Dekker <martijn@inlv.org>, Groningen, Netherlands 16# 17# Permission to use, copy, modify, and/or distribute this software for any 18# purpose with or without fee is hereby granted, provided that the above 19# copyright notice and this permission notice appear in all copies. 20# 21# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 22# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 23# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 24# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 25# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 26# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 27# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 28# --- end license --- 29 30if thisshellhas PSREPLACE; then 31 # bash, *ksh, zsh, yash: we can use ${var/"x"/"y"} and ${var//"x"/"y"} 32 replacein() { 33 case ${#},${1-},${2-} in 34 ( 3,,"${2-}" | 3,[0123456789]*,"${2-}" | 3,*[!"$ASCIIALNUM"_]*,"${2-}" ) 35 die "replacein: invalid variable name: $1" ;; 36 ( 4,-[ta], | 4,-[ta],[0123456789]* | 4,-[ta],*[!"$ASCIIALNUM"_]* ) 37 die "replacein: invalid variable name: $2" ;; 38 ( 3,* ) eval "$1=\${$1/\"\$2\"/\"\$3\"}" ;; 39 ( 4,-t,* ) 40 eval "if str in \"\$$2\" \"\$3\"; then 41 $2=\${$2%\"\$3\"*}\$4\${$2##*\"\$3\"} 42 fi" ;; 43 ( 4,-a,* ) 44 eval "$2=\${$2//\"\$3\"/\"\$4\"}" ;; 45 ( * ) die "replacein: invalid arguments" ;; 46 esac 47 } 48else 49 # POSIX: 50 replacein() { 51 case ${#},${1-},${2-} in 52 ( 3,,"${2-}" | 3,[0123456789]*,"${2-}" | 3,*[!"$ASCIIALNUM"_]*,"${2-}" ) 53 die "replacein: invalid variable name: $1" ;; 54 ( 4,-[ta], | 4,-[ta],[0123456789]* | 4,-[ta],*[!"$ASCIIALNUM"_]* ) 55 die "replacein: invalid variable name: $2" ;; 56 ( 3,* ) eval "if str in \"\$$1\" \"\$2\"; then 57 $1=\${$1%%\"\$2\"*}\$3\${$1#*\"\$2\"} 58 fi" ;; 59 ( 4,-t,* ) 60 eval "if str in \"\$$2\" \"\$3\"; then 61 $2=\${$2%\"\$3\"*}\$4\${$2##*\"\$3\"} 62 fi" ;; 63 ( 4,-a,* ) 64 if str in "$4" "$3"; then 65 # use a temporary variable to avoid an infinite loop when 66 # replacing all of one character by one or more of itself 67 # (e.g. "replacein -a somevariable / //") 68 eval "_Msh_rAi=\$$2 69 $2= 70 while str in \"\${_Msh_rAi}\" \"\$3\"; do 71 $2=\$$2\${_Msh_rAi%%\"\$3\"*}\$4 72 _Msh_rAi=\${_Msh_rAi#*\"\$3\"} 73 done 74 $2=\$$2\${_Msh_rAi}" 75 unset -v _Msh_rAi 76 else 77 # use faster algorithm without extra variable 78 eval "while str in \"\$$2\" \"\$3\"; do 79 $2=\${$2%%\"\$3\"*}\$4\${$2#*\"\$3\"} 80 done" 81 fi ;; 82 ( * ) die "replacein: invalid arguments" ;; 83 esac 84 } 85fi 86 87if thisshellhas ROFUNC; then 88 readonly -f replacein 89fi 90