Skip to content

Commit d1fb20c

Browse files
committed
Rewrite "info variables" to support line feeds and spaces in values, array keys and array values.
Bash's "typeset -p" escapes line feeds and other special characters and wraps such values in $''. Array keys with spaces are wrapped into "". Previously, $'' was kept but the escape codes were resolved. The escape codes are now retained in the output of "info variables" to show each variable and its value on a single line. This is to improve readability and help programmatic parsing of the variable listing.
1 parent dda77ff commit d1fb20c

File tree

2 files changed

+95
-135
lines changed

2 files changed

+95
-135
lines changed

command/info_sub/variables.sh

Lines changed: 80 additions & 135 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
# with bashdb; see the file COPYING. If not, write to the Free Software
1818
# Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA.
1919

20-
2120
# V [![pat]] List variables and values for whose variables names which
2221
# match pat $1. If ! is used, list variables that *don't* match.
2322
# If pat ($1) is omitted, use * (everything) for the pattern.
@@ -56,147 +55,93 @@ See also:
5655
5756
' 1
5857

59-
if ! typeset -F getopts_long >/dev/null 2>&1 ; then
58+
if ! typeset -F getopts_long >/dev/null 2>&1; then
59+
# shellcheck source=./../../getopts_long.sh
6060
. "${_Dbg_libdir}/getopts_long.sh"
6161
fi
6262

63-
# Should declare typset_flags before calling.
64-
# That it the implit returned value
65-
function _Dbg_info_variables_parse_options {
66-
67-
typeset -i _Dbg_rc=0
63+
function _Dbg_do_info_variables {
64+
declare _Dbg_typeset_flags=""
65+
declare -i _Dbg_typeset_filtered=1
66+
_Dbg_info_variables_parse_options "$@"
67+
(($? != 0)) && return
68+
69+
# Create an indexed array of variable names which are matching our input flags,
70+
# use a single pipeline command to avoid later evaluation of the output by Bash.
71+
declare -a _Dbg_var_names=()
72+
if ((_Dbg_typeset_filtered == 1)); then
73+
# grepping for '=' to only accept variables with a value
74+
mapfile -t _Dbg_var_names < <(declare -p $_Dbg_typeset_flags |
75+
grep '=' |
76+
grep -o '^declare -[^ ]\+ [^=]\+' |
77+
cut -d ' ' -f 3- |
78+
grep -v '^_Dbg_\|^_$\|^*$' |
79+
sort -f 2>/dev/null)
80+
else
81+
mapfile -t _Dbg_var_names < <(declare -p $_Dbg_typeset_flags |
82+
grep -o '^declare -[^ ]\+ [^=]\+' |
83+
cut -d ' ' -f 3- |
84+
grep -v '^_Dbg_\|^_$\|^*$' |
85+
sort -f 2>/dev/null)
86+
fi
87+
88+
(($? != 0 || ${#_Dbg_var_names} == 0)) && return
89+
90+
declare -i _Dbg_skipped_fields
91+
((_Dbg_skipped_fields = _Dbg_typeset_filtered + 2))
92+
93+
declare _Dbg_declare_output
94+
_Dbg_declare_output="$(declare -p "${_Dbg_var_names[@]}" | cut -d ' ' -s -f ${_Dbg_skipped_fields}- 2>/dev/null)"
95+
(($? != 0)) && return
96+
97+
_Dbg_msg_verbatim "$_Dbg_declare_output"
98+
}
6899

100+
# Parse flags passed to the "info variables" command.
101+
# The caller should declare _Dbg_typeset_flags and _Dbg_typeset_filtered before calling,
102+
# which are implicitly returned values.
103+
function _Dbg_info_variables_parse_options {
69104
_Dbg_typeset_flags=""
70105
_Dbg_typeset_filtered=1
71106

72-
OPTLIND=''
73-
while getopts_long irxaAtp opt \
74-
integer no_argument \
75-
readonly no_argument \
76-
exports no_argument \
77-
indexed no_argument \
78-
associative no_argument \
79-
trace no_argument \
80-
properties no_argument \
81-
'' $@
82-
do
83-
case "$opt" in
84-
i | integer )
85-
_Dbg_typeset_flags="-i $_Dbg_typeset_flags";;
86-
r | readonly )
87-
_Dbg_typeset_flags="-r _$_Dbg_typeset_flags";;
88-
x | exports )
89-
_Dbg_typeset_flags="-x $_Dbg_typeset_flags";;
90-
a | indexed )
91-
_Dbg_typeset_flags="-a $_Dbg_typeset_flags";;
92-
A | associative )
93-
_Dbg_typeset_flags="-A $_Dbg_typeset_flags";;
94-
t | trace )
95-
_Dbg_typeset_flags="-t $_Dbg_typeset_flags";;
96-
p | properties )
97-
_Dbg_typeset_filtered=0;;
98-
* )
99-
_Dbg_errmsg "Invalid argument in $@; use only -x, -i, -r, -a, -A, -t, or -p"
100-
_Dbg_rc=1
101-
;;
102-
esac
107+
typeset -i _Dbg_rc=0
108+
typeset OPTLIND=''
109+
while getopts_long irxaAtp opt \
110+
integer no_argument \
111+
readonly no_argument \
112+
exports no_argument \
113+
indexed no_argument \
114+
associative no_argument \
115+
trace no_argument \
116+
properties no_argument \
117+
'' "$*"; do
118+
case "$opt" in
119+
i | integer)
120+
_Dbg_typeset_flags="-i $_Dbg_typeset_flags"
121+
;;
122+
r | readonly)
123+
_Dbg_typeset_flags="-r $_Dbg_typeset_flags"
124+
;;
125+
x | exports)
126+
_Dbg_typeset_flags="-x $_Dbg_typeset_flags"
127+
;;
128+
a | indexed)
129+
_Dbg_typeset_flags="-a $_Dbg_typeset_flags"
130+
;;
131+
A | associative)
132+
_Dbg_typeset_flags="-A $_Dbg_typeset_flags"
133+
;;
134+
t | trace)
135+
_Dbg_typeset_flags="-t $_Dbg_typeset_flags"
136+
;;
137+
p | properties)
138+
_Dbg_typeset_filtered=0
139+
;;
140+
*)
141+
_Dbg_errmsg "Invalid argument in $*; use only -x, -i, -r, -a, -A, -t, or -p"
142+
_Dbg_rc=1
143+
;;
144+
esac
103145
done
104146
return $_Dbg_rc
105147
}
106-
107-
function _Dbg_do_info_variables {
108-
_Dbg_typeset_flags=""
109-
local -i _Dbg_typeset_filtered=1
110-
_Dbg_info_variables_parse_options "$@"
111-
(( $? != 0 )) && return
112-
113-
local _Dbg_old_glob="$GLOBIGNORE"
114-
GLOBIGNORE="*"
115-
116-
_Dbg_match='*'
117-
local _Dbg_list=$(declare -p $_Dbg_typeset_flags)
118-
local _Dbg_old_ifs=${IFS}
119-
IFS="
120-
"
121-
local _Dbg_temp=${_Dbg_list}
122-
_Dbg_list=""
123-
local -i _Dbg_i=0
124-
local -a _Dbg_list
125-
126-
# GLOBIGNORE protects us against using the result of
127-
# a glob expansion, but it doesn't protect us from
128-
# actually performing it, and this can bring bash down
129-
# with a huge _Dbg_source_ variable being globbed.
130-
# So here we disable globbing momentarily
131-
set -o noglob
132-
for _Dbg_item in ${_Dbg_temp}; do
133-
_Dbg_list[${_Dbg_i}]="${_Dbg_item}"
134-
_Dbg_i=${_Dbg_i}+1
135-
done
136-
set +o noglob
137-
IFS=${_Dbg_old_ifs}
138-
local _Dbg_item=""
139-
local _Dbg_skip=0
140-
local _Dbg_show_cmd=""
141-
_Dbg_show_cmd=`echo -e "case \\${_Dbg_item} in \n${_Dbg_match})\n echo yes;;\n*)\necho no;; esac"`
142-
143-
for (( _Dbg_i=0; (( _Dbg_i < ${#_Dbg_list[@]} )) ; _Dbg_i++ )) ; do
144-
_Dbg_item=${_Dbg_list[$_Dbg_i]}
145-
146-
147-
# Ignore all _Dbg_ variables here because the following
148-
# substitutions takes a long while when it encounters
149-
# a big _Dbg_source_
150-
if [[ ${_Dbg_item} =~ "_Dbg_" ]] ; then
151-
continue;
152-
fi
153-
154-
155-
case ${_Dbg_item} in
156-
*\ \(\)\ )
157-
_Dbg_skip=1
158-
;;
159-
\})
160-
_Dbg_skip=0
161-
continue
162-
esac
163-
if [[ _Dbg_skip -eq 1 ]]; then
164-
continue
165-
fi
166-
_Dbg_item=${_Dbg_item/=/==/}
167-
_Dbg_item=${_Dbg_item%%=[^=]*}
168-
case ${_Dbg_item} in
169-
_=);;
170-
*=)
171-
_Dbg_item=${_Dbg_item%=}
172-
local _Dbg_show=`eval $_Dbg_show_cmd`
173-
if [[ "$_Dbg_show" != "$_Dbg_match_inverted" ]]; then
174-
if [[ -n ${_Dbg_item} ]]; then
175-
local _Dbg_var=`declare -p ${_Dbg_typeset_flags} ${_Dbg_item} 2>/dev/null`
176-
if [[ -n "$_Dbg_var" ]]; then
177-
# Uncomment the following 3 lines to use literal
178-
# linefeeds
179-
# _Dbg_var=${_Dbg_var//\\\\n/\\n}
180-
# _Dbg_var=${_Dbg_var//
181-
#/\n}
182-
# Comment the following 3 lines to use literal linefeeds
183-
_Dbg_var=${_Dbg_var//\\\\n/\\\\\\n}
184-
_Dbg_var=${_Dbg_var//
185-
/\\n}
186-
if (( _Dbg_typeset_filtered == 1 )); then
187-
_Dbg_var=${_Dbg_var#* * }
188-
else
189-
_Dbg_var=${_Dbg_var#* }
190-
fi
191-
_Dbg_msg ${_Dbg_var}
192-
fi
193-
fi
194-
fi
195-
;;
196-
*)
197-
;;
198-
esac
199-
200-
done
201-
GLOBIGNORE=$_Dbg_old_glob
202-
}

lib/msg.sh

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,21 @@ function _Dbg_printf_nocr {
131131
fi
132132
}
133133

134+
# Like _Dbg_msg but does not evaluate escape sequences which are embedded in the arguments
135+
# print message to output device
136+
function _Dbg_msg_verbatim {
137+
if (( _Dbg_logging )) ; then
138+
builtin echo -E "$@" >>$_Dbg_logging_file
139+
fi
140+
if (( ! _Dbg_logging_redirect )) ; then
141+
if [[ -n $_Dbg_tty ]] && [[ $_Dbg_tty != '&1' ]] ; then
142+
builtin echo -E "$@" >>$_Dbg_tty
143+
else
144+
builtin echo -E "$@"
145+
fi
146+
fi
147+
}
148+
134149
typeset _Dbg_dashes='---------------------------------------------------'
135150

136151
# print message to output device

0 commit comments

Comments
 (0)