1: 2# RCSid: 3# $Id: safe_eval.sh,v 1.26 2026/04/10 16:03:39 sjg Exp $ 4# 5# @(#) Copyright (c) 2023-2026 Simon J. Gerraty 6# 7# SPDX-License-Identifier: BSD-2-Clause 8# 9# Please send copies of changes and bug-fixes to: 10# sjg@crufty.net 11 12_SAFE_EVAL_SH=: 13 14# does local *actually* work? 15local_works() { 16 local _fu 17} 18 19if local_works > /dev/null 2>&1; then 20 _local=local 21else 22 _local=: 23fi 24 25## 26# safe_set [xtras] 27# 28# return a safe variable setting 29# any non-alphanumeric chars other than those in "xtras" 30# will be replaced with '_' 31# 32# "xtras" should be used with caution and cannot include ';' 33# 34safe_set() { 35 ${SED:-sed} 's/[ ]*#.*//;/^[A-Za-z_][A-Za-z0-9_]*=/!d;s;[^A-Za-z0-9_. "'"$1"'$,/=:+-];_;g' 36} 37 38## 39# safe_eval [file] 40# 41# eval variable assignments only from file 42# taking care to eliminate any shell meta chars 43# 44safe_eval() { 45 eval `cat "$@" | safe_set` 46} 47 48## 49# safe_eval_export [file] 50# 51# eval variable assignments only from file 52# taking care to eliminate any shell meta chars 53# export any variables thus set 54# 55safe_eval_export() { 56 eval `cat "$@" | safe_set | ${SED:-sed} 's/^\([^=]*\)=.*/&; export \1/'` 57} 58 59## 60# safe_dot file [...] 61# 62# feed all "file" that exist to safe_eval 63# 64safe_dot() { 65 eval $_local ef ex f rc 66 ef= 67 ex= 68 rc=1 69 while : 70 do 71 case "$1" in 72 --export) ex=_export; shift;; 73 *) break;; 74 esac 75 done 76 for f in "$@" 77 do 78 test -s "$f" -a -f "$f" || continue 79 : check for space or tab in "$f" 80 case "$f" in 81 *[[:space:]]*|*" "*|*" "*) # we cannot do this efficiently 82 dotted="$dotted $f" 83 safe_eval$ex "$f" 84 rc=$? 85 continue 86 ;; 87 esac 88 ef="${ef:+$ef }$f" 89 dotted="$dotted $f" 90 done 91 test -z "$ef" && return $rc 92 safe_eval$ex $ef 93 return 0 94} 95 96case /$0 in 97*/safe_eval*) 98 case "$1" in 99 dot|eval|set) op=safe_$1; shift; $op "$@";; 100 *) safe_dot "$@";; 101 esac 102 ;; 103esac 104