1: 2# RCSid: 3# $Id: safe_eval.sh,v 1.25 2025/08/07 22:13:03 sjg Exp $ 4# 5# @(#) Copyright (c) 2023-2024 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 27# 28# return a safe variable setting 29# any non-alphanumeric chars are replaced with '_' 30# 31safe_set() { 32 ${SED:-sed} 's/[ ]*#.*//;/^[A-Za-z_][A-Za-z0-9_]*=/!d;s;[^A-Za-z0-9_. "$,/=:+-];_;g' 33} 34 35## 36# safe_eval [file] 37# 38# eval variable assignments only from file 39# taking care to eliminate any shell meta chars 40# 41safe_eval() { 42 eval `cat "$@" | safe_set` 43} 44 45## 46# safe_eval_export [file] 47# 48# eval variable assignments only from file 49# taking care to eliminate any shell meta chars 50# export any variables thus set 51# 52safe_eval_export() { 53 eval `cat "$@" | safe_set | ${SED:-sed} 's/^\([^=]*\)=.*/&; export \1/'` 54} 55 56## 57# safe_dot file [...] 58# 59# feed all "file" that exist to safe_eval 60# 61safe_dot() { 62 eval $_local ef ex f rc 63 ef= 64 ex= 65 rc=1 66 while : 67 do 68 case "$1" in 69 --export) ex=_export; shift;; 70 *) break;; 71 esac 72 done 73 for f in "$@" 74 do 75 test -s "$f" -a -f "$f" || continue 76 : check for space or tab in "$f" 77 case "$f" in 78 *[[:space:]]*|*" "*|*" "*) # we cannot do this efficiently 79 dotted="$dotted $f" 80 safe_eval$ex "$f" 81 rc=$? 82 continue 83 ;; 84 esac 85 ef="${ef:+$ef }$f" 86 dotted="$dotted $f" 87 done 88 test -z "$ef" && return $rc 89 safe_eval$ex $ef 90 return 0 91} 92 93case /$0 in 94*/safe_eval*) 95 case "$1" in 96 dot|eval|set) op=safe_$1; shift; $op "$@";; 97 *) safe_dot "$@";; 98 esac 99 ;; 100esac 101