Napisałem podobną funkcję POSIX, ale nie ryzykuje to wykonania dowolnego kodu:
unexport()
while case ${1##[0-9]*} in ### rule out leading numerics
(*[!_[:alnum:]]*|"") ### filter out bad|empty names
set "" ${1+"bad name: '$1'"} ### prep bad name error
return ${2+${1:?"$2"}} ### fail w/ above err or return
esac
do eval set '"$'"{$1+$1}"'" "$'"$1"'" "$'@\" ### $1 = ( $1+ ? $1 : "" )
eval "${1:+unset $1;$1=\$2;} shift 3" ### $$1 = ( $1:+ ? $2 : -- )
done
Będzie również obsługiwał tyle argumentów, ile chcesz. Jeśli argument jest prawidłową nazwą, która nie jest jeszcze ustawiona, jest dyskretnie ignorowany. Jeśli argument jest złą nazwą, zapisuje go do stderr i zatrzymuje odpowiednio, chociaż każda poprawna nazwa poprzedzająca niepoprawną w wierszu poleceń będzie nadal przetwarzana.
Myślałem o innym sposobie. Bardziej mi się podoba.
unexport()
while unset OPTARG; OPTIND=1 ### always work w/ $1
case ${1##[0-9]*} in ### same old same old
(*[!_[:alnum:]]*|"") ### goodname && $# > 0 || break
${1+"getopts"} : "$1" ### $# ? getopts : ":"
return ### getopts errored or ":" didnt
esac
do eval getopts :s: '"$1" -"${'"$1+s}-\$$1\""
eval unset "$1; ${OPTARG+$1=\${OPTARG}#-}"
shift
done
Oba wykorzystują wiele takich samych technik. Zasadniczo, jeśli zmienna powłoki jest rozbrojona, odniesienie do niej nie będzie rozszerzane wraz z +
rozszerzaniem parametrów. Ale jeśli jest ustawiony - niezależnie od jego wartości - rozszerzenie parametru takie jak: ${parameter+word}
zostanie rozwinięte do word
- a nie do wartości zmiennej. Tak więc zmienne powłoki wykonują autotest i zastępują się sukcesem.
Mogą również zawieść . W górnej funkcji, jeśli zostanie znaleziona zła nazwa, przechodzę $1
do $2
i pozostawiam $1
null, ponieważ następną rzeczą, którą robię, jest albo return
sukces, jeśli wszystkie argumenty zostały przetworzone i pętla jest na końcu, lub, jeśli argument był nieprawidłowy, powłoka będzie rozwiń, $2
w $1:?
który zabije skryptowaną powłokę i zwróci przerwanie do interaktywnej podczas pisania word
do stderr.
W drugim getopts
wykonuje się zadania. I nie przypisuje złej nazwy - raczej napisz, wypisze standardowy komunikat o błędzie do stderr. Co więcej, zapisuje wartość arg, $OPTARG
jeśli argument był w pierwszej kolejności nazwą zmiennej ustawionej. Po zrobieniu getopts
wszystko, co jest potrzebne, to rozszerzenie eval
zestawu OPTARG
do odpowiedniego zadania.
mktemp
jeśli jest on wystarczająco przenośny, i rozbroić wartość, a następnie pobrać plik tymczasowy, aby przypisać zmienną. Można utworzyć przynajmniej plik tymczasowy o mniej więcej dowolnej nazwie w przeciwieństwie do zmiennej powłoki.