Op 22-10-16 om 17:04 schreef Janis Papanagnou:
> Curious; how do you make that match, cross-platform and using
> individual shell's features?
In this particular case, using a combination of:
- a test 'eval' in a subshell to determine if the shell has the relevant
zsh-style parameter expansion;
- wrapping the function definitions that use this feature in 'eval' so
they don't cause syntax errors on other shells;
- and using the modernish thisshellhas() function, which (among other
things, like running bug/feature tests and caching their results) is
capable of checking for the presence of a reserved word on all POSIX shells.
Below is my code for defining the internal functions that handle
'isset -x', the option for 'isset' to check if a variable is exported.
If you want to know how thisshellhas() or other things work, go to
Github and read the code, or just grab a copy (disclaimers: under heavy
development, no release version exists yet, breakage and incompatible
changes *will* happen, keep 'git pull'-ing and reading 'git log' and
'git log -p'):
$ git clone
https://github.com/modernish/modernish
$ modernish/install.sh # if /bin/sh is POSIX compliant
$ dash modernish/install.sh # otherwise use a shell that is
$ . modernish # for interactive use
Documentation (such as it is) is in README.md and share/doc/modernish/,
but at this point you just may have to read the code as well. Bug
reports and constructive criticism are welcome!
Oops. I think I just made the first public announcement. Oh well, here
goes nothing...
- M.
(Note: _Msh_* is the namespace for internal functions and variables that
shall not be touched or directly used by programs using the library.)
___begin code (warning: long lines; I'm long over the 80s)___
# Internal functions for isset -x
if isset ZSH_VERSION && ( eval ': ${(t)PATH}' ) 2>/dev/null; then
# zsh makes this trivial: ${(t)VARNAME} (dash-separated)
contains 'export',
# and the P in ${(Pt)1} means: use the variable name stored in
$1. Good thing
# because 'export' on zsh is a reserved word we cannot alias
(see below).
if thisshellhas --rw=[[; then
# '[[' could have been disabled with 'disable -r' so
don't assume it.
eval '_Msh_issetEx() {
[[ -${(Pt)1}- == *-export-* ]]
}'
else # If you disable POSIX keywords like 'case', you never
even get this far.
eval '_Msh_issetEx() {
case -${(Pt)1}- in ( *-export-* ) ;; ( * )
return 1 ;; esac
}'
fi
elif ! thisshellhas --rw=export; then
# On other shells, we must use trickery to reliably parse the
output of 'export -p'.
# The 'export -p' command in POSIX shells produces 'export'
commands (even on bash, as
# long as the shell is in POSIX mode, which it must be to run
modernish). Grepping this
# output is not reliably possible because entries may be split
in multiple lines. We
# must get the shell to parse it. The only way to do this is to
temporarily alias
# 'export' to a handler function. This only works if 'export' is
not a reserved word.
_Msh_issetEx() {
unset -v _Msh_issetEx_WasRun _Msh_issetEx_FoundIt
export _Msh_issetEx_Dummy=foo # guarantee one exported
variable to check if this method works
_Msh_issetExV=$1
alias export=_Msh_issetExHandleExport
eval "$(command export -p)"
unalias export
unset -v _Msh_issetExV _Msh_issetEx_Dummy
isset _Msh_issetEx_WasRun && unset -v _Msh_issetEx_WasRun ||
die "isset -x: internal error: 'export -p' not
parseable (is shell in POSIX mode?)" || return
isset _Msh_issetEx_FoundIt && unset -v _Msh_issetEx_FoundIt
}
_Msh_issetExHandleExport() {
_Msh_issetEx_WasRun=''
case ${1%%=*} in
("${_Msh_issetExV}") _Msh_issetEx_FoundIt='' ;;
esac
}
else _Msh_initExit "init: isset -x: Can't determine method to test if
a var. is exported." \
"This shell has 'export' as a reserved word, but
modernish was only" \
"programmed to handle this on zsh. Please report this as
a bug in modernish."
fi
___end code___