Check variable is an array in Bourne like shell?
Clash Royale CLAN TAG#URR8PPP
In Bourne like shell which support array variable, we can use some parsing to check if variable is an array.
All commands below were run after running a=(1 2 3)
.
zsh
:
$ declare -p a
typeset -a a
a=( 1 2 3 )
bash
:
$ declare -p a
declare -a a='([0]="1" [1]="2" [2]="3")'
ksh93
:
$ typeset -p a
typeset -a a=(1 2 3)
pdksh
and its derivative:
$ typeset -p a
set -A a
typeset a[0]=1
typeset a[1]=2
typeset a[2]=3
yash
:
$ typeset -p a
a=('1' '2' '3')
typeset a
An example in bash
:
if declare -p var 2>/dev/null | grep -q 'declare -a'; then
echo array variable
fi
This approach is too much work and need to spawn a subshell. Using other shell builtin like =~
in [[ ... ]]
do not need a subshell, but is still too complicated.
Is there easier way to accomplish this task?
bash shell zsh ksh yash
add a comment |
In Bourne like shell which support array variable, we can use some parsing to check if variable is an array.
All commands below were run after running a=(1 2 3)
.
zsh
:
$ declare -p a
typeset -a a
a=( 1 2 3 )
bash
:
$ declare -p a
declare -a a='([0]="1" [1]="2" [2]="3")'
ksh93
:
$ typeset -p a
typeset -a a=(1 2 3)
pdksh
and its derivative:
$ typeset -p a
set -A a
typeset a[0]=1
typeset a[1]=2
typeset a[2]=3
yash
:
$ typeset -p a
a=('1' '2' '3')
typeset a
An example in bash
:
if declare -p var 2>/dev/null | grep -q 'declare -a'; then
echo array variable
fi
This approach is too much work and need to spawn a subshell. Using other shell builtin like =~
in [[ ... ]]
do not need a subshell, but is still too complicated.
Is there easier way to accomplish this task?
bash shell zsh ksh yash
Under what circumstances would you need to check whether your variables are arrays or not?
– Kusalananda
Dec 20 '18 at 10:07
add a comment |
In Bourne like shell which support array variable, we can use some parsing to check if variable is an array.
All commands below were run after running a=(1 2 3)
.
zsh
:
$ declare -p a
typeset -a a
a=( 1 2 3 )
bash
:
$ declare -p a
declare -a a='([0]="1" [1]="2" [2]="3")'
ksh93
:
$ typeset -p a
typeset -a a=(1 2 3)
pdksh
and its derivative:
$ typeset -p a
set -A a
typeset a[0]=1
typeset a[1]=2
typeset a[2]=3
yash
:
$ typeset -p a
a=('1' '2' '3')
typeset a
An example in bash
:
if declare -p var 2>/dev/null | grep -q 'declare -a'; then
echo array variable
fi
This approach is too much work and need to spawn a subshell. Using other shell builtin like =~
in [[ ... ]]
do not need a subshell, but is still too complicated.
Is there easier way to accomplish this task?
bash shell zsh ksh yash
In Bourne like shell which support array variable, we can use some parsing to check if variable is an array.
All commands below were run after running a=(1 2 3)
.
zsh
:
$ declare -p a
typeset -a a
a=( 1 2 3 )
bash
:
$ declare -p a
declare -a a='([0]="1" [1]="2" [2]="3")'
ksh93
:
$ typeset -p a
typeset -a a=(1 2 3)
pdksh
and its derivative:
$ typeset -p a
set -A a
typeset a[0]=1
typeset a[1]=2
typeset a[2]=3
yash
:
$ typeset -p a
a=('1' '2' '3')
typeset a
An example in bash
:
if declare -p var 2>/dev/null | grep -q 'declare -a'; then
echo array variable
fi
This approach is too much work and need to spawn a subshell. Using other shell builtin like =~
in [[ ... ]]
do not need a subshell, but is still too complicated.
Is there easier way to accomplish this task?
bash shell zsh ksh yash
bash shell zsh ksh yash
edited Nov 28 '15 at 17:21
asked Nov 28 '15 at 4:04
cuonglm
102k23201301
102k23201301
Under what circumstances would you need to check whether your variables are arrays or not?
– Kusalananda
Dec 20 '18 at 10:07
add a comment |
Under what circumstances would you need to check whether your variables are arrays or not?
– Kusalananda
Dec 20 '18 at 10:07
Under what circumstances would you need to check whether your variables are arrays or not?
– Kusalananda
Dec 20 '18 at 10:07
Under what circumstances would you need to check whether your variables are arrays or not?
– Kusalananda
Dec 20 '18 at 10:07
add a comment |
8 Answers
8
active
oldest
votes
I don't think you can, and I don't think it actually makes any difference.
unset a
a=x
echo "$a[0]-not array"
x
That does the same thing in either of ksh93
and bash
. It looks like possibly all variables are arrays in those shells, or at least any regular variable which has not been assigned special attributes, but I didn't check much of that.
The bash
manual talks about different behaviors for an array versus a string variable when using +=
assignments, but it afterwards hedges and states that the the array only behaves differently in a compound assignment context.
It also states that a variable is considered an array if any subscript has been assigned a value - and explicitly includes the possibility of a null-string. Above you can see that a regular assignment definitely results in a subscript being assigned - and so I guess everything is an array.
Practically, possibly you can use:
[ 1 = "$a[0]+$#a[@]" ] && echo not array
...to clearly pinpoint set variables that have only been assigned a single subscript of value 0.
So I guess checking if$a[1]-not array
can do the task, can't it?
– cuonglm
Nov 28 '15 at 4:58
@cuonglm - Well, not according to thebash
manual: An array variable is considered set if a subscript has been assigned a value. The null string is a valid value. If any subscript is assigned its an array per spec. In practice, also no, because you can doa[5]=x
. I guess[ 1 -eq "$#a[@]" ] && [ -n "$a[0]+1" ]
could work.
– mikeserv
Nov 28 '15 at 5:03
add a comment |
So you effectively want just the middle part of declare -p
without the junk around it?
You could write a macro such as:
readonly VARTYPE=' read __;
case "`declare -p "$__"`" in
"declare -a"*) echo array;;
"declare -A"*) echo hash;;
"declare -- "*) echo scalar;;
esac;
<<<'
so that you can do:
a=scalar
b=( array )
declare -A c; c[hashKey]=hashValue;
######################################
eval "$VARTYPE" a #scalar
eval "$VARTYPE" b #array
eval "$VARTYPE" c #hash
(A mere function won't do if you'll want to use this on function-local variables).
With aliases
shopt -s expand_aliases
alias vartype='eval "$VARTYPE"'
vartype a #scalar
vartype b #array
vartype c #hash
@mikeserv Good point. Aliases make it look prettier. +1
– PSkocik
Nov 28 '15 at 19:41
i meant -alias vartype="$VARTYPE"
... or just not defining the$VARTYPE
at all - it should work, right? you only should need thatshopt
thing inbash
because it breaks with the spec regardingalias
expansion in scripts.
– mikeserv
Nov 28 '15 at 19:42
1
@mikeserv I'm sure cuonglm is well capable of tweaking this approach to his needs and preferences. ;-)
– PSkocik
Nov 28 '15 at 19:46
... and security considerations.
– PSkocik
Nov 28 '15 at 19:47
At no point does the above code eval user provided text. It's no less secure than a function. I've never seen you fussing about making functions read-only, but OK, I can mark the variable readonly.
– PSkocik
Nov 28 '15 at 20:06
|
show 1 more comment
In zsh
zsh% a=(1 2 3) s=1
zsh% [[ $(t)a == *array* ]] && echo array
array
zsh% [[ $(t)s == *array* ]] && echo array
zsh%
Maybeecho $(t)var
is simpler. Thanks for this.
– user79743
Nov 28 '15 at 21:00
add a comment |
To test variable var, with
b=("$!var[@]")
c="$#b[@]"
It is possible to test if there are more than one array index:
[[ $c > 1 ]] && echo "Var is an array"
If the first index value is not zero:
[[ $b[0] -eq 0 ]] && echo "Var is an array" ## should be 1 for zsh.
The only hard confusion is when there is only one index value and that value is zero (or one).
For that condition, it is possible to use a side effect of trying to remove an array element from a variable that is not an array:
**bash** reports an error with unset var[0]
bash: unset: var: not an array variable
**zsh** also reports an error with $ var[1]=()
attempt to assign array value to non-array
This works correctly for bash:
# Test if the value at index 0 could be unset.
# If it fails, the variable is not an array.
( unset "var[0]" 2>/dev/null; ) && echo "var is an array."
For zsh the index may need to be 1 (unless a compatible mode is active).
The sub-shell is needed to avoid the side effect of erasing index 0 of var.
I have found no way to make it work in ksh.
Edit 1
This function only works in bash4.2+
getVarType() $varname=*) echo scalar; ;;
esac;
var=( foo bar ); getVarType var
Edit 2
This also work only for bash4.2+
typeset -p var && echo "var is an array"
Note: This will give false positives if var contains the tested strings.
How about array with zero elements?
– cuonglm
Nov 28 '15 at 8:32
1
Dat edit, tho. Looks very original. :D
– PSkocik
Nov 28 '15 at 20:30
@cuonglm The check( unset "var[0]" 2>/dev/null; ) && echo "var is an array."
correctly reports var is an array when var has been set tovar=()
an array with zero elements. It acts exactly equal to declare.
– user79743
Nov 29 '15 at 12:53
The test for scalar won't work if the scalar is exported or marked integer/lowercase/readonly... You can probably safely make it that any other non-empty output means scalar variable. I'd usegrep -E
instead ofgrep -P
to avoid the dependency on GNU grep.
– Stéphane Chazelas
Nov 30 '15 at 9:30
@StéphaneChazelas The test (in bash) for scalar with integer and/or lowercase and /or readonly always start with-a
, like this:declare -airl var='()'
. Therefore the grep test will work.
– user79743
Nov 30 '15 at 17:32
|
show 3 more comments
For bash, it's a little bit of a hack (albeit documented): attempt to use typeset
to remove the "array" attribute:
$ typeset +a BASH_VERSINFO
bash: typeset: BASH_VERSINFO: cannot destroy array variables in this way
echo $?
1
(You cannot do this in zsh
, it allows you to convert an array to a scalar, in bash
it's explicitly forbidden.)
So:
typeset +A myvariable 2>/dev/null || echo is assoc-array
typeset +a myvariable 2>/dev/null || echo is array
Or in a function, noting the caveats at the end:
function typeof()
local _myvar="$1"
if ! typeset -p $_myvar 2>/dev/null ; then
echo no-such
elif ! typeset -g +A $_myvar 2>/dev/null ; then
echo is-assoc-array
elif ! typeset -g +a $_myvar 2>/dev/null; then
echo is-array
else
echo scalar
fi
Note the use of typeset -g
(bash-4.2 or later), this is required within a function so that typeset
(syn. declare
) doesn't work like local
and clobber the value you are trying to inspect. This also does not handle function "variable" types, you can add another branch test using typeset -f
if needed.
Another (nearly complete) option is to use this:
$!name[*]
If name is an array variable, expands to the list
of array indices (keys) assigned in name. If name
is not an array, expands to 0 if name is set and
null otherwise. When @ is used and the expansion
appears within double quotes, each key expands to a
separate word.
There's one slight problem though, an array with a single subscript of 0 matches two of the above conditions. This is something that mikeserv also references, bash really doesn't have a hard distinction, and some of this (if you check the Changelog) can be blamed on ksh and compatibilty with how $name[*]
or $name[@]
behave on a non-array.
So a partial solution is:
if [[ $!BASH_VERSINFO[*] == '' ]]; then
echo no-such
elif [[ $!BASH_VERSINFO[*] == '0' ]]; then
echo not-array
elif [[ $!BASH_VERSINFO[*] != '0' ]];
echo is-array
fi
I have used in the past a variation on this:
while read _line; do
if [[ $_line =~ ^"declare -a" ]]; then
...
fi
done < <( declare -p )
this too needs a subshell though.
One more possibly useful technique is compgen
:
compgen -A arrayvar
This will list all indexed arrays, however associative arrays are not handled specially (up to bash-4.4) and appear as regular variables (compgen -A variable
)
Thetypeset +a
also reports an error in ksh. Not in zsh, though.
– user79743
Nov 28 '15 at 20:38
add a comment |
Short answer:
For the two shells that introduced this notation (bash
and ksh93
) a scalar variable is just an array with a single element.
Neither needs a special declaration to create an array. Just the assignment is enough, and a plain assignment var=value
is identical to var[0]=value
.
Try:bash -c 'unset var; var=foo; typeset -p var'
. Do bash answer report an array (needs an -a)?. Now compare with:bash -c 'unset var; var[12]=foo; typeset -p var'
. Why is there a difference?. A: The shell maintains (for good or for bad) a notion of which vars are scalars or arrays. The shell ksh do mix both concepts into one.
– user79743
Nov 29 '15 at 23:23
add a comment |
yash's array
builtin has some options that only work with array variables. Example: the -d
option will report an error on non-array variable:
$ a=123
$ array -d a
array: no such array $a
So we can do something like this:
is_array() (
array -d -- "$1"
) >/dev/null 2>&1
a=(1 2 3)
if is_array a; then
echo array
fi
b=123
if ! is_array b; then
echo not array
fi
This approach won't work if array variable is readonly. Trying to modify a readonly variable leading to an error:
$ a=()
$ readonly a
$ array -d a
array: $a is read-only
add a comment |
#!/bin/bash
var=BASH_SOURCE
[[ "$(declare -pa)" =~ [^[:alpha:]]$var= ]]
case "$?" in
0)
echo "$var is an array variable"
;;
1)
echo "$var is not an array variable"
;;
*)
echo "Unknown exit code"
;;
esac
add a comment |
Your Answer
StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "106"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);
else
createEditor();
);
function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);
);
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f246026%2fcheck-variable-is-an-array-in-bourne-like-shell%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
8 Answers
8
active
oldest
votes
8 Answers
8
active
oldest
votes
active
oldest
votes
active
oldest
votes
I don't think you can, and I don't think it actually makes any difference.
unset a
a=x
echo "$a[0]-not array"
x
That does the same thing in either of ksh93
and bash
. It looks like possibly all variables are arrays in those shells, or at least any regular variable which has not been assigned special attributes, but I didn't check much of that.
The bash
manual talks about different behaviors for an array versus a string variable when using +=
assignments, but it afterwards hedges and states that the the array only behaves differently in a compound assignment context.
It also states that a variable is considered an array if any subscript has been assigned a value - and explicitly includes the possibility of a null-string. Above you can see that a regular assignment definitely results in a subscript being assigned - and so I guess everything is an array.
Practically, possibly you can use:
[ 1 = "$a[0]+$#a[@]" ] && echo not array
...to clearly pinpoint set variables that have only been assigned a single subscript of value 0.
So I guess checking if$a[1]-not array
can do the task, can't it?
– cuonglm
Nov 28 '15 at 4:58
@cuonglm - Well, not according to thebash
manual: An array variable is considered set if a subscript has been assigned a value. The null string is a valid value. If any subscript is assigned its an array per spec. In practice, also no, because you can doa[5]=x
. I guess[ 1 -eq "$#a[@]" ] && [ -n "$a[0]+1" ]
could work.
– mikeserv
Nov 28 '15 at 5:03
add a comment |
I don't think you can, and I don't think it actually makes any difference.
unset a
a=x
echo "$a[0]-not array"
x
That does the same thing in either of ksh93
and bash
. It looks like possibly all variables are arrays in those shells, or at least any regular variable which has not been assigned special attributes, but I didn't check much of that.
The bash
manual talks about different behaviors for an array versus a string variable when using +=
assignments, but it afterwards hedges and states that the the array only behaves differently in a compound assignment context.
It also states that a variable is considered an array if any subscript has been assigned a value - and explicitly includes the possibility of a null-string. Above you can see that a regular assignment definitely results in a subscript being assigned - and so I guess everything is an array.
Practically, possibly you can use:
[ 1 = "$a[0]+$#a[@]" ] && echo not array
...to clearly pinpoint set variables that have only been assigned a single subscript of value 0.
So I guess checking if$a[1]-not array
can do the task, can't it?
– cuonglm
Nov 28 '15 at 4:58
@cuonglm - Well, not according to thebash
manual: An array variable is considered set if a subscript has been assigned a value. The null string is a valid value. If any subscript is assigned its an array per spec. In practice, also no, because you can doa[5]=x
. I guess[ 1 -eq "$#a[@]" ] && [ -n "$a[0]+1" ]
could work.
– mikeserv
Nov 28 '15 at 5:03
add a comment |
I don't think you can, and I don't think it actually makes any difference.
unset a
a=x
echo "$a[0]-not array"
x
That does the same thing in either of ksh93
and bash
. It looks like possibly all variables are arrays in those shells, or at least any regular variable which has not been assigned special attributes, but I didn't check much of that.
The bash
manual talks about different behaviors for an array versus a string variable when using +=
assignments, but it afterwards hedges and states that the the array only behaves differently in a compound assignment context.
It also states that a variable is considered an array if any subscript has been assigned a value - and explicitly includes the possibility of a null-string. Above you can see that a regular assignment definitely results in a subscript being assigned - and so I guess everything is an array.
Practically, possibly you can use:
[ 1 = "$a[0]+$#a[@]" ] && echo not array
...to clearly pinpoint set variables that have only been assigned a single subscript of value 0.
I don't think you can, and I don't think it actually makes any difference.
unset a
a=x
echo "$a[0]-not array"
x
That does the same thing in either of ksh93
and bash
. It looks like possibly all variables are arrays in those shells, or at least any regular variable which has not been assigned special attributes, but I didn't check much of that.
The bash
manual talks about different behaviors for an array versus a string variable when using +=
assignments, but it afterwards hedges and states that the the array only behaves differently in a compound assignment context.
It also states that a variable is considered an array if any subscript has been assigned a value - and explicitly includes the possibility of a null-string. Above you can see that a regular assignment definitely results in a subscript being assigned - and so I guess everything is an array.
Practically, possibly you can use:
[ 1 = "$a[0]+$#a[@]" ] && echo not array
...to clearly pinpoint set variables that have only been assigned a single subscript of value 0.
edited Nov 28 '15 at 5:09
answered Nov 28 '15 at 4:52
mikeserv
45.3k567153
45.3k567153
So I guess checking if$a[1]-not array
can do the task, can't it?
– cuonglm
Nov 28 '15 at 4:58
@cuonglm - Well, not according to thebash
manual: An array variable is considered set if a subscript has been assigned a value. The null string is a valid value. If any subscript is assigned its an array per spec. In practice, also no, because you can doa[5]=x
. I guess[ 1 -eq "$#a[@]" ] && [ -n "$a[0]+1" ]
could work.
– mikeserv
Nov 28 '15 at 5:03
add a comment |
So I guess checking if$a[1]-not array
can do the task, can't it?
– cuonglm
Nov 28 '15 at 4:58
@cuonglm - Well, not according to thebash
manual: An array variable is considered set if a subscript has been assigned a value. The null string is a valid value. If any subscript is assigned its an array per spec. In practice, also no, because you can doa[5]=x
. I guess[ 1 -eq "$#a[@]" ] && [ -n "$a[0]+1" ]
could work.
– mikeserv
Nov 28 '15 at 5:03
So I guess checking if
$a[1]-not array
can do the task, can't it?– cuonglm
Nov 28 '15 at 4:58
So I guess checking if
$a[1]-not array
can do the task, can't it?– cuonglm
Nov 28 '15 at 4:58
@cuonglm - Well, not according to the
bash
manual: An array variable is considered set if a subscript has been assigned a value. The null string is a valid value. If any subscript is assigned its an array per spec. In practice, also no, because you can do a[5]=x
. I guess [ 1 -eq "$#a[@]" ] && [ -n "$a[0]+1" ]
could work.– mikeserv
Nov 28 '15 at 5:03
@cuonglm - Well, not according to the
bash
manual: An array variable is considered set if a subscript has been assigned a value. The null string is a valid value. If any subscript is assigned its an array per spec. In practice, also no, because you can do a[5]=x
. I guess [ 1 -eq "$#a[@]" ] && [ -n "$a[0]+1" ]
could work.– mikeserv
Nov 28 '15 at 5:03
add a comment |
So you effectively want just the middle part of declare -p
without the junk around it?
You could write a macro such as:
readonly VARTYPE=' read __;
case "`declare -p "$__"`" in
"declare -a"*) echo array;;
"declare -A"*) echo hash;;
"declare -- "*) echo scalar;;
esac;
<<<'
so that you can do:
a=scalar
b=( array )
declare -A c; c[hashKey]=hashValue;
######################################
eval "$VARTYPE" a #scalar
eval "$VARTYPE" b #array
eval "$VARTYPE" c #hash
(A mere function won't do if you'll want to use this on function-local variables).
With aliases
shopt -s expand_aliases
alias vartype='eval "$VARTYPE"'
vartype a #scalar
vartype b #array
vartype c #hash
@mikeserv Good point. Aliases make it look prettier. +1
– PSkocik
Nov 28 '15 at 19:41
i meant -alias vartype="$VARTYPE"
... or just not defining the$VARTYPE
at all - it should work, right? you only should need thatshopt
thing inbash
because it breaks with the spec regardingalias
expansion in scripts.
– mikeserv
Nov 28 '15 at 19:42
1
@mikeserv I'm sure cuonglm is well capable of tweaking this approach to his needs and preferences. ;-)
– PSkocik
Nov 28 '15 at 19:46
... and security considerations.
– PSkocik
Nov 28 '15 at 19:47
At no point does the above code eval user provided text. It's no less secure than a function. I've never seen you fussing about making functions read-only, but OK, I can mark the variable readonly.
– PSkocik
Nov 28 '15 at 20:06
|
show 1 more comment
So you effectively want just the middle part of declare -p
without the junk around it?
You could write a macro such as:
readonly VARTYPE=' read __;
case "`declare -p "$__"`" in
"declare -a"*) echo array;;
"declare -A"*) echo hash;;
"declare -- "*) echo scalar;;
esac;
<<<'
so that you can do:
a=scalar
b=( array )
declare -A c; c[hashKey]=hashValue;
######################################
eval "$VARTYPE" a #scalar
eval "$VARTYPE" b #array
eval "$VARTYPE" c #hash
(A mere function won't do if you'll want to use this on function-local variables).
With aliases
shopt -s expand_aliases
alias vartype='eval "$VARTYPE"'
vartype a #scalar
vartype b #array
vartype c #hash
@mikeserv Good point. Aliases make it look prettier. +1
– PSkocik
Nov 28 '15 at 19:41
i meant -alias vartype="$VARTYPE"
... or just not defining the$VARTYPE
at all - it should work, right? you only should need thatshopt
thing inbash
because it breaks with the spec regardingalias
expansion in scripts.
– mikeserv
Nov 28 '15 at 19:42
1
@mikeserv I'm sure cuonglm is well capable of tweaking this approach to his needs and preferences. ;-)
– PSkocik
Nov 28 '15 at 19:46
... and security considerations.
– PSkocik
Nov 28 '15 at 19:47
At no point does the above code eval user provided text. It's no less secure than a function. I've never seen you fussing about making functions read-only, but OK, I can mark the variable readonly.
– PSkocik
Nov 28 '15 at 20:06
|
show 1 more comment
So you effectively want just the middle part of declare -p
without the junk around it?
You could write a macro such as:
readonly VARTYPE=' read __;
case "`declare -p "$__"`" in
"declare -a"*) echo array;;
"declare -A"*) echo hash;;
"declare -- "*) echo scalar;;
esac;
<<<'
so that you can do:
a=scalar
b=( array )
declare -A c; c[hashKey]=hashValue;
######################################
eval "$VARTYPE" a #scalar
eval "$VARTYPE" b #array
eval "$VARTYPE" c #hash
(A mere function won't do if you'll want to use this on function-local variables).
With aliases
shopt -s expand_aliases
alias vartype='eval "$VARTYPE"'
vartype a #scalar
vartype b #array
vartype c #hash
So you effectively want just the middle part of declare -p
without the junk around it?
You could write a macro such as:
readonly VARTYPE=' read __;
case "`declare -p "$__"`" in
"declare -a"*) echo array;;
"declare -A"*) echo hash;;
"declare -- "*) echo scalar;;
esac;
<<<'
so that you can do:
a=scalar
b=( array )
declare -A c; c[hashKey]=hashValue;
######################################
eval "$VARTYPE" a #scalar
eval "$VARTYPE" b #array
eval "$VARTYPE" c #hash
(A mere function won't do if you'll want to use this on function-local variables).
With aliases
shopt -s expand_aliases
alias vartype='eval "$VARTYPE"'
vartype a #scalar
vartype b #array
vartype c #hash
edited Nov 28 '15 at 20:06
answered Nov 28 '15 at 11:47
PSkocik
17.8k44994
17.8k44994
@mikeserv Good point. Aliases make it look prettier. +1
– PSkocik
Nov 28 '15 at 19:41
i meant -alias vartype="$VARTYPE"
... or just not defining the$VARTYPE
at all - it should work, right? you only should need thatshopt
thing inbash
because it breaks with the spec regardingalias
expansion in scripts.
– mikeserv
Nov 28 '15 at 19:42
1
@mikeserv I'm sure cuonglm is well capable of tweaking this approach to his needs and preferences. ;-)
– PSkocik
Nov 28 '15 at 19:46
... and security considerations.
– PSkocik
Nov 28 '15 at 19:47
At no point does the above code eval user provided text. It's no less secure than a function. I've never seen you fussing about making functions read-only, but OK, I can mark the variable readonly.
– PSkocik
Nov 28 '15 at 20:06
|
show 1 more comment
@mikeserv Good point. Aliases make it look prettier. +1
– PSkocik
Nov 28 '15 at 19:41
i meant -alias vartype="$VARTYPE"
... or just not defining the$VARTYPE
at all - it should work, right? you only should need thatshopt
thing inbash
because it breaks with the spec regardingalias
expansion in scripts.
– mikeserv
Nov 28 '15 at 19:42
1
@mikeserv I'm sure cuonglm is well capable of tweaking this approach to his needs and preferences. ;-)
– PSkocik
Nov 28 '15 at 19:46
... and security considerations.
– PSkocik
Nov 28 '15 at 19:47
At no point does the above code eval user provided text. It's no less secure than a function. I've never seen you fussing about making functions read-only, but OK, I can mark the variable readonly.
– PSkocik
Nov 28 '15 at 20:06
@mikeserv Good point. Aliases make it look prettier. +1
– PSkocik
Nov 28 '15 at 19:41
@mikeserv Good point. Aliases make it look prettier. +1
– PSkocik
Nov 28 '15 at 19:41
i meant -
alias vartype="$VARTYPE"
... or just not defining the $VARTYPE
at all - it should work, right? you only should need that shopt
thing in bash
because it breaks with the spec regarding alias
expansion in scripts.– mikeserv
Nov 28 '15 at 19:42
i meant -
alias vartype="$VARTYPE"
... or just not defining the $VARTYPE
at all - it should work, right? you only should need that shopt
thing in bash
because it breaks with the spec regarding alias
expansion in scripts.– mikeserv
Nov 28 '15 at 19:42
1
1
@mikeserv I'm sure cuonglm is well capable of tweaking this approach to his needs and preferences. ;-)
– PSkocik
Nov 28 '15 at 19:46
@mikeserv I'm sure cuonglm is well capable of tweaking this approach to his needs and preferences. ;-)
– PSkocik
Nov 28 '15 at 19:46
... and security considerations.
– PSkocik
Nov 28 '15 at 19:47
... and security considerations.
– PSkocik
Nov 28 '15 at 19:47
At no point does the above code eval user provided text. It's no less secure than a function. I've never seen you fussing about making functions read-only, but OK, I can mark the variable readonly.
– PSkocik
Nov 28 '15 at 20:06
At no point does the above code eval user provided text. It's no less secure than a function. I've never seen you fussing about making functions read-only, but OK, I can mark the variable readonly.
– PSkocik
Nov 28 '15 at 20:06
|
show 1 more comment
In zsh
zsh% a=(1 2 3) s=1
zsh% [[ $(t)a == *array* ]] && echo array
array
zsh% [[ $(t)s == *array* ]] && echo array
zsh%
Maybeecho $(t)var
is simpler. Thanks for this.
– user79743
Nov 28 '15 at 21:00
add a comment |
In zsh
zsh% a=(1 2 3) s=1
zsh% [[ $(t)a == *array* ]] && echo array
array
zsh% [[ $(t)s == *array* ]] && echo array
zsh%
Maybeecho $(t)var
is simpler. Thanks for this.
– user79743
Nov 28 '15 at 21:00
add a comment |
In zsh
zsh% a=(1 2 3) s=1
zsh% [[ $(t)a == *array* ]] && echo array
array
zsh% [[ $(t)s == *array* ]] && echo array
zsh%
In zsh
zsh% a=(1 2 3) s=1
zsh% [[ $(t)a == *array* ]] && echo array
array
zsh% [[ $(t)s == *array* ]] && echo array
zsh%
answered Nov 28 '15 at 20:16
llua
4,6991420
4,6991420
Maybeecho $(t)var
is simpler. Thanks for this.
– user79743
Nov 28 '15 at 21:00
add a comment |
Maybeecho $(t)var
is simpler. Thanks for this.
– user79743
Nov 28 '15 at 21:00
Maybe
echo $(t)var
is simpler. Thanks for this.– user79743
Nov 28 '15 at 21:00
Maybe
echo $(t)var
is simpler. Thanks for this.– user79743
Nov 28 '15 at 21:00
add a comment |
To test variable var, with
b=("$!var[@]")
c="$#b[@]"
It is possible to test if there are more than one array index:
[[ $c > 1 ]] && echo "Var is an array"
If the first index value is not zero:
[[ $b[0] -eq 0 ]] && echo "Var is an array" ## should be 1 for zsh.
The only hard confusion is when there is only one index value and that value is zero (or one).
For that condition, it is possible to use a side effect of trying to remove an array element from a variable that is not an array:
**bash** reports an error with unset var[0]
bash: unset: var: not an array variable
**zsh** also reports an error with $ var[1]=()
attempt to assign array value to non-array
This works correctly for bash:
# Test if the value at index 0 could be unset.
# If it fails, the variable is not an array.
( unset "var[0]" 2>/dev/null; ) && echo "var is an array."
For zsh the index may need to be 1 (unless a compatible mode is active).
The sub-shell is needed to avoid the side effect of erasing index 0 of var.
I have found no way to make it work in ksh.
Edit 1
This function only works in bash4.2+
getVarType() $varname=*) echo scalar; ;;
esac;
var=( foo bar ); getVarType var
Edit 2
This also work only for bash4.2+
typeset -p var && echo "var is an array"
Note: This will give false positives if var contains the tested strings.
How about array with zero elements?
– cuonglm
Nov 28 '15 at 8:32
1
Dat edit, tho. Looks very original. :D
– PSkocik
Nov 28 '15 at 20:30
@cuonglm The check( unset "var[0]" 2>/dev/null; ) && echo "var is an array."
correctly reports var is an array when var has been set tovar=()
an array with zero elements. It acts exactly equal to declare.
– user79743
Nov 29 '15 at 12:53
The test for scalar won't work if the scalar is exported or marked integer/lowercase/readonly... You can probably safely make it that any other non-empty output means scalar variable. I'd usegrep -E
instead ofgrep -P
to avoid the dependency on GNU grep.
– Stéphane Chazelas
Nov 30 '15 at 9:30
@StéphaneChazelas The test (in bash) for scalar with integer and/or lowercase and /or readonly always start with-a
, like this:declare -airl var='()'
. Therefore the grep test will work.
– user79743
Nov 30 '15 at 17:32
|
show 3 more comments
To test variable var, with
b=("$!var[@]")
c="$#b[@]"
It is possible to test if there are more than one array index:
[[ $c > 1 ]] && echo "Var is an array"
If the first index value is not zero:
[[ $b[0] -eq 0 ]] && echo "Var is an array" ## should be 1 for zsh.
The only hard confusion is when there is only one index value and that value is zero (or one).
For that condition, it is possible to use a side effect of trying to remove an array element from a variable that is not an array:
**bash** reports an error with unset var[0]
bash: unset: var: not an array variable
**zsh** also reports an error with $ var[1]=()
attempt to assign array value to non-array
This works correctly for bash:
# Test if the value at index 0 could be unset.
# If it fails, the variable is not an array.
( unset "var[0]" 2>/dev/null; ) && echo "var is an array."
For zsh the index may need to be 1 (unless a compatible mode is active).
The sub-shell is needed to avoid the side effect of erasing index 0 of var.
I have found no way to make it work in ksh.
Edit 1
This function only works in bash4.2+
getVarType() $varname=*) echo scalar; ;;
esac;
var=( foo bar ); getVarType var
Edit 2
This also work only for bash4.2+
typeset -p var && echo "var is an array"
Note: This will give false positives if var contains the tested strings.
How about array with zero elements?
– cuonglm
Nov 28 '15 at 8:32
1
Dat edit, tho. Looks very original. :D
– PSkocik
Nov 28 '15 at 20:30
@cuonglm The check( unset "var[0]" 2>/dev/null; ) && echo "var is an array."
correctly reports var is an array when var has been set tovar=()
an array with zero elements. It acts exactly equal to declare.
– user79743
Nov 29 '15 at 12:53
The test for scalar won't work if the scalar is exported or marked integer/lowercase/readonly... You can probably safely make it that any other non-empty output means scalar variable. I'd usegrep -E
instead ofgrep -P
to avoid the dependency on GNU grep.
– Stéphane Chazelas
Nov 30 '15 at 9:30
@StéphaneChazelas The test (in bash) for scalar with integer and/or lowercase and /or readonly always start with-a
, like this:declare -airl var='()'
. Therefore the grep test will work.
– user79743
Nov 30 '15 at 17:32
|
show 3 more comments
To test variable var, with
b=("$!var[@]")
c="$#b[@]"
It is possible to test if there are more than one array index:
[[ $c > 1 ]] && echo "Var is an array"
If the first index value is not zero:
[[ $b[0] -eq 0 ]] && echo "Var is an array" ## should be 1 for zsh.
The only hard confusion is when there is only one index value and that value is zero (or one).
For that condition, it is possible to use a side effect of trying to remove an array element from a variable that is not an array:
**bash** reports an error with unset var[0]
bash: unset: var: not an array variable
**zsh** also reports an error with $ var[1]=()
attempt to assign array value to non-array
This works correctly for bash:
# Test if the value at index 0 could be unset.
# If it fails, the variable is not an array.
( unset "var[0]" 2>/dev/null; ) && echo "var is an array."
For zsh the index may need to be 1 (unless a compatible mode is active).
The sub-shell is needed to avoid the side effect of erasing index 0 of var.
I have found no way to make it work in ksh.
Edit 1
This function only works in bash4.2+
getVarType() $varname=*) echo scalar; ;;
esac;
var=( foo bar ); getVarType var
Edit 2
This also work only for bash4.2+
typeset -p var && echo "var is an array"
Note: This will give false positives if var contains the tested strings.
To test variable var, with
b=("$!var[@]")
c="$#b[@]"
It is possible to test if there are more than one array index:
[[ $c > 1 ]] && echo "Var is an array"
If the first index value is not zero:
[[ $b[0] -eq 0 ]] && echo "Var is an array" ## should be 1 for zsh.
The only hard confusion is when there is only one index value and that value is zero (or one).
For that condition, it is possible to use a side effect of trying to remove an array element from a variable that is not an array:
**bash** reports an error with unset var[0]
bash: unset: var: not an array variable
**zsh** also reports an error with $ var[1]=()
attempt to assign array value to non-array
This works correctly for bash:
# Test if the value at index 0 could be unset.
# If it fails, the variable is not an array.
( unset "var[0]" 2>/dev/null; ) && echo "var is an array."
For zsh the index may need to be 1 (unless a compatible mode is active).
The sub-shell is needed to avoid the side effect of erasing index 0 of var.
I have found no way to make it work in ksh.
Edit 1
This function only works in bash4.2+
getVarType() $varname=*) echo scalar; ;;
esac;
var=( foo bar ); getVarType var
Edit 2
This also work only for bash4.2+
typeset -p var && echo "var is an array"
Note: This will give false positives if var contains the tested strings.
edited Nov 29 '15 at 23:08
answered Nov 28 '15 at 8:30
user79743
How about array with zero elements?
– cuonglm
Nov 28 '15 at 8:32
1
Dat edit, tho. Looks very original. :D
– PSkocik
Nov 28 '15 at 20:30
@cuonglm The check( unset "var[0]" 2>/dev/null; ) && echo "var is an array."
correctly reports var is an array when var has been set tovar=()
an array with zero elements. It acts exactly equal to declare.
– user79743
Nov 29 '15 at 12:53
The test for scalar won't work if the scalar is exported or marked integer/lowercase/readonly... You can probably safely make it that any other non-empty output means scalar variable. I'd usegrep -E
instead ofgrep -P
to avoid the dependency on GNU grep.
– Stéphane Chazelas
Nov 30 '15 at 9:30
@StéphaneChazelas The test (in bash) for scalar with integer and/or lowercase and /or readonly always start with-a
, like this:declare -airl var='()'
. Therefore the grep test will work.
– user79743
Nov 30 '15 at 17:32
|
show 3 more comments
How about array with zero elements?
– cuonglm
Nov 28 '15 at 8:32
1
Dat edit, tho. Looks very original. :D
– PSkocik
Nov 28 '15 at 20:30
@cuonglm The check( unset "var[0]" 2>/dev/null; ) && echo "var is an array."
correctly reports var is an array when var has been set tovar=()
an array with zero elements. It acts exactly equal to declare.
– user79743
Nov 29 '15 at 12:53
The test for scalar won't work if the scalar is exported or marked integer/lowercase/readonly... You can probably safely make it that any other non-empty output means scalar variable. I'd usegrep -E
instead ofgrep -P
to avoid the dependency on GNU grep.
– Stéphane Chazelas
Nov 30 '15 at 9:30
@StéphaneChazelas The test (in bash) for scalar with integer and/or lowercase and /or readonly always start with-a
, like this:declare -airl var='()'
. Therefore the grep test will work.
– user79743
Nov 30 '15 at 17:32
How about array with zero elements?
– cuonglm
Nov 28 '15 at 8:32
How about array with zero elements?
– cuonglm
Nov 28 '15 at 8:32
1
1
Dat edit, tho. Looks very original. :D
– PSkocik
Nov 28 '15 at 20:30
Dat edit, tho. Looks very original. :D
– PSkocik
Nov 28 '15 at 20:30
@cuonglm The check
( unset "var[0]" 2>/dev/null; ) && echo "var is an array."
correctly reports var is an array when var has been set to var=()
an array with zero elements. It acts exactly equal to declare.– user79743
Nov 29 '15 at 12:53
@cuonglm The check
( unset "var[0]" 2>/dev/null; ) && echo "var is an array."
correctly reports var is an array when var has been set to var=()
an array with zero elements. It acts exactly equal to declare.– user79743
Nov 29 '15 at 12:53
The test for scalar won't work if the scalar is exported or marked integer/lowercase/readonly... You can probably safely make it that any other non-empty output means scalar variable. I'd use
grep -E
instead of grep -P
to avoid the dependency on GNU grep.– Stéphane Chazelas
Nov 30 '15 at 9:30
The test for scalar won't work if the scalar is exported or marked integer/lowercase/readonly... You can probably safely make it that any other non-empty output means scalar variable. I'd use
grep -E
instead of grep -P
to avoid the dependency on GNU grep.– Stéphane Chazelas
Nov 30 '15 at 9:30
@StéphaneChazelas The test (in bash) for scalar with integer and/or lowercase and /or readonly always start with
-a
, like this: declare -airl var='()'
. Therefore the grep test will work.– user79743
Nov 30 '15 at 17:32
@StéphaneChazelas The test (in bash) for scalar with integer and/or lowercase and /or readonly always start with
-a
, like this: declare -airl var='()'
. Therefore the grep test will work.– user79743
Nov 30 '15 at 17:32
|
show 3 more comments
For bash, it's a little bit of a hack (albeit documented): attempt to use typeset
to remove the "array" attribute:
$ typeset +a BASH_VERSINFO
bash: typeset: BASH_VERSINFO: cannot destroy array variables in this way
echo $?
1
(You cannot do this in zsh
, it allows you to convert an array to a scalar, in bash
it's explicitly forbidden.)
So:
typeset +A myvariable 2>/dev/null || echo is assoc-array
typeset +a myvariable 2>/dev/null || echo is array
Or in a function, noting the caveats at the end:
function typeof()
local _myvar="$1"
if ! typeset -p $_myvar 2>/dev/null ; then
echo no-such
elif ! typeset -g +A $_myvar 2>/dev/null ; then
echo is-assoc-array
elif ! typeset -g +a $_myvar 2>/dev/null; then
echo is-array
else
echo scalar
fi
Note the use of typeset -g
(bash-4.2 or later), this is required within a function so that typeset
(syn. declare
) doesn't work like local
and clobber the value you are trying to inspect. This also does not handle function "variable" types, you can add another branch test using typeset -f
if needed.
Another (nearly complete) option is to use this:
$!name[*]
If name is an array variable, expands to the list
of array indices (keys) assigned in name. If name
is not an array, expands to 0 if name is set and
null otherwise. When @ is used and the expansion
appears within double quotes, each key expands to a
separate word.
There's one slight problem though, an array with a single subscript of 0 matches two of the above conditions. This is something that mikeserv also references, bash really doesn't have a hard distinction, and some of this (if you check the Changelog) can be blamed on ksh and compatibilty with how $name[*]
or $name[@]
behave on a non-array.
So a partial solution is:
if [[ $!BASH_VERSINFO[*] == '' ]]; then
echo no-such
elif [[ $!BASH_VERSINFO[*] == '0' ]]; then
echo not-array
elif [[ $!BASH_VERSINFO[*] != '0' ]];
echo is-array
fi
I have used in the past a variation on this:
while read _line; do
if [[ $_line =~ ^"declare -a" ]]; then
...
fi
done < <( declare -p )
this too needs a subshell though.
One more possibly useful technique is compgen
:
compgen -A arrayvar
This will list all indexed arrays, however associative arrays are not handled specially (up to bash-4.4) and appear as regular variables (compgen -A variable
)
Thetypeset +a
also reports an error in ksh. Not in zsh, though.
– user79743
Nov 28 '15 at 20:38
add a comment |
For bash, it's a little bit of a hack (albeit documented): attempt to use typeset
to remove the "array" attribute:
$ typeset +a BASH_VERSINFO
bash: typeset: BASH_VERSINFO: cannot destroy array variables in this way
echo $?
1
(You cannot do this in zsh
, it allows you to convert an array to a scalar, in bash
it's explicitly forbidden.)
So:
typeset +A myvariable 2>/dev/null || echo is assoc-array
typeset +a myvariable 2>/dev/null || echo is array
Or in a function, noting the caveats at the end:
function typeof()
local _myvar="$1"
if ! typeset -p $_myvar 2>/dev/null ; then
echo no-such
elif ! typeset -g +A $_myvar 2>/dev/null ; then
echo is-assoc-array
elif ! typeset -g +a $_myvar 2>/dev/null; then
echo is-array
else
echo scalar
fi
Note the use of typeset -g
(bash-4.2 or later), this is required within a function so that typeset
(syn. declare
) doesn't work like local
and clobber the value you are trying to inspect. This also does not handle function "variable" types, you can add another branch test using typeset -f
if needed.
Another (nearly complete) option is to use this:
$!name[*]
If name is an array variable, expands to the list
of array indices (keys) assigned in name. If name
is not an array, expands to 0 if name is set and
null otherwise. When @ is used and the expansion
appears within double quotes, each key expands to a
separate word.
There's one slight problem though, an array with a single subscript of 0 matches two of the above conditions. This is something that mikeserv also references, bash really doesn't have a hard distinction, and some of this (if you check the Changelog) can be blamed on ksh and compatibilty with how $name[*]
or $name[@]
behave on a non-array.
So a partial solution is:
if [[ $!BASH_VERSINFO[*] == '' ]]; then
echo no-such
elif [[ $!BASH_VERSINFO[*] == '0' ]]; then
echo not-array
elif [[ $!BASH_VERSINFO[*] != '0' ]];
echo is-array
fi
I have used in the past a variation on this:
while read _line; do
if [[ $_line =~ ^"declare -a" ]]; then
...
fi
done < <( declare -p )
this too needs a subshell though.
One more possibly useful technique is compgen
:
compgen -A arrayvar
This will list all indexed arrays, however associative arrays are not handled specially (up to bash-4.4) and appear as regular variables (compgen -A variable
)
Thetypeset +a
also reports an error in ksh. Not in zsh, though.
– user79743
Nov 28 '15 at 20:38
add a comment |
For bash, it's a little bit of a hack (albeit documented): attempt to use typeset
to remove the "array" attribute:
$ typeset +a BASH_VERSINFO
bash: typeset: BASH_VERSINFO: cannot destroy array variables in this way
echo $?
1
(You cannot do this in zsh
, it allows you to convert an array to a scalar, in bash
it's explicitly forbidden.)
So:
typeset +A myvariable 2>/dev/null || echo is assoc-array
typeset +a myvariable 2>/dev/null || echo is array
Or in a function, noting the caveats at the end:
function typeof()
local _myvar="$1"
if ! typeset -p $_myvar 2>/dev/null ; then
echo no-such
elif ! typeset -g +A $_myvar 2>/dev/null ; then
echo is-assoc-array
elif ! typeset -g +a $_myvar 2>/dev/null; then
echo is-array
else
echo scalar
fi
Note the use of typeset -g
(bash-4.2 or later), this is required within a function so that typeset
(syn. declare
) doesn't work like local
and clobber the value you are trying to inspect. This also does not handle function "variable" types, you can add another branch test using typeset -f
if needed.
Another (nearly complete) option is to use this:
$!name[*]
If name is an array variable, expands to the list
of array indices (keys) assigned in name. If name
is not an array, expands to 0 if name is set and
null otherwise. When @ is used and the expansion
appears within double quotes, each key expands to a
separate word.
There's one slight problem though, an array with a single subscript of 0 matches two of the above conditions. This is something that mikeserv also references, bash really doesn't have a hard distinction, and some of this (if you check the Changelog) can be blamed on ksh and compatibilty with how $name[*]
or $name[@]
behave on a non-array.
So a partial solution is:
if [[ $!BASH_VERSINFO[*] == '' ]]; then
echo no-such
elif [[ $!BASH_VERSINFO[*] == '0' ]]; then
echo not-array
elif [[ $!BASH_VERSINFO[*] != '0' ]];
echo is-array
fi
I have used in the past a variation on this:
while read _line; do
if [[ $_line =~ ^"declare -a" ]]; then
...
fi
done < <( declare -p )
this too needs a subshell though.
One more possibly useful technique is compgen
:
compgen -A arrayvar
This will list all indexed arrays, however associative arrays are not handled specially (up to bash-4.4) and appear as regular variables (compgen -A variable
)
For bash, it's a little bit of a hack (albeit documented): attempt to use typeset
to remove the "array" attribute:
$ typeset +a BASH_VERSINFO
bash: typeset: BASH_VERSINFO: cannot destroy array variables in this way
echo $?
1
(You cannot do this in zsh
, it allows you to convert an array to a scalar, in bash
it's explicitly forbidden.)
So:
typeset +A myvariable 2>/dev/null || echo is assoc-array
typeset +a myvariable 2>/dev/null || echo is array
Or in a function, noting the caveats at the end:
function typeof()
local _myvar="$1"
if ! typeset -p $_myvar 2>/dev/null ; then
echo no-such
elif ! typeset -g +A $_myvar 2>/dev/null ; then
echo is-assoc-array
elif ! typeset -g +a $_myvar 2>/dev/null; then
echo is-array
else
echo scalar
fi
Note the use of typeset -g
(bash-4.2 or later), this is required within a function so that typeset
(syn. declare
) doesn't work like local
and clobber the value you are trying to inspect. This also does not handle function "variable" types, you can add another branch test using typeset -f
if needed.
Another (nearly complete) option is to use this:
$!name[*]
If name is an array variable, expands to the list
of array indices (keys) assigned in name. If name
is not an array, expands to 0 if name is set and
null otherwise. When @ is used and the expansion
appears within double quotes, each key expands to a
separate word.
There's one slight problem though, an array with a single subscript of 0 matches two of the above conditions. This is something that mikeserv also references, bash really doesn't have a hard distinction, and some of this (if you check the Changelog) can be blamed on ksh and compatibilty with how $name[*]
or $name[@]
behave on a non-array.
So a partial solution is:
if [[ $!BASH_VERSINFO[*] == '' ]]; then
echo no-such
elif [[ $!BASH_VERSINFO[*] == '0' ]]; then
echo not-array
elif [[ $!BASH_VERSINFO[*] != '0' ]];
echo is-array
fi
I have used in the past a variation on this:
while read _line; do
if [[ $_line =~ ^"declare -a" ]]; then
...
fi
done < <( declare -p )
this too needs a subshell though.
One more possibly useful technique is compgen
:
compgen -A arrayvar
This will list all indexed arrays, however associative arrays are not handled specially (up to bash-4.4) and appear as regular variables (compgen -A variable
)
edited Oct 5 '17 at 12:19
answered Nov 28 '15 at 16:39
mr.spuratic
6,7761028
6,7761028
Thetypeset +a
also reports an error in ksh. Not in zsh, though.
– user79743
Nov 28 '15 at 20:38
add a comment |
Thetypeset +a
also reports an error in ksh. Not in zsh, though.
– user79743
Nov 28 '15 at 20:38
The
typeset +a
also reports an error in ksh. Not in zsh, though.– user79743
Nov 28 '15 at 20:38
The
typeset +a
also reports an error in ksh. Not in zsh, though.– user79743
Nov 28 '15 at 20:38
add a comment |
Short answer:
For the two shells that introduced this notation (bash
and ksh93
) a scalar variable is just an array with a single element.
Neither needs a special declaration to create an array. Just the assignment is enough, and a plain assignment var=value
is identical to var[0]=value
.
Try:bash -c 'unset var; var=foo; typeset -p var'
. Do bash answer report an array (needs an -a)?. Now compare with:bash -c 'unset var; var[12]=foo; typeset -p var'
. Why is there a difference?. A: The shell maintains (for good or for bad) a notion of which vars are scalars or arrays. The shell ksh do mix both concepts into one.
– user79743
Nov 29 '15 at 23:23
add a comment |
Short answer:
For the two shells that introduced this notation (bash
and ksh93
) a scalar variable is just an array with a single element.
Neither needs a special declaration to create an array. Just the assignment is enough, and a plain assignment var=value
is identical to var[0]=value
.
Try:bash -c 'unset var; var=foo; typeset -p var'
. Do bash answer report an array (needs an -a)?. Now compare with:bash -c 'unset var; var[12]=foo; typeset -p var'
. Why is there a difference?. A: The shell maintains (for good or for bad) a notion of which vars are scalars or arrays. The shell ksh do mix both concepts into one.
– user79743
Nov 29 '15 at 23:23
add a comment |
Short answer:
For the two shells that introduced this notation (bash
and ksh93
) a scalar variable is just an array with a single element.
Neither needs a special declaration to create an array. Just the assignment is enough, and a plain assignment var=value
is identical to var[0]=value
.
Short answer:
For the two shells that introduced this notation (bash
and ksh93
) a scalar variable is just an array with a single element.
Neither needs a special declaration to create an array. Just the assignment is enough, and a plain assignment var=value
is identical to var[0]=value
.
answered Nov 29 '15 at 22:41
Henk Langeveld
567213
567213
Try:bash -c 'unset var; var=foo; typeset -p var'
. Do bash answer report an array (needs an -a)?. Now compare with:bash -c 'unset var; var[12]=foo; typeset -p var'
. Why is there a difference?. A: The shell maintains (for good or for bad) a notion of which vars are scalars or arrays. The shell ksh do mix both concepts into one.
– user79743
Nov 29 '15 at 23:23
add a comment |
Try:bash -c 'unset var; var=foo; typeset -p var'
. Do bash answer report an array (needs an -a)?. Now compare with:bash -c 'unset var; var[12]=foo; typeset -p var'
. Why is there a difference?. A: The shell maintains (for good or for bad) a notion of which vars are scalars or arrays. The shell ksh do mix both concepts into one.
– user79743
Nov 29 '15 at 23:23
Try:
bash -c 'unset var; var=foo; typeset -p var'
. Do bash answer report an array (needs an -a)?. Now compare with: bash -c 'unset var; var[12]=foo; typeset -p var'
. Why is there a difference?. A: The shell maintains (for good or for bad) a notion of which vars are scalars or arrays. The shell ksh do mix both concepts into one.– user79743
Nov 29 '15 at 23:23
Try:
bash -c 'unset var; var=foo; typeset -p var'
. Do bash answer report an array (needs an -a)?. Now compare with: bash -c 'unset var; var[12]=foo; typeset -p var'
. Why is there a difference?. A: The shell maintains (for good or for bad) a notion of which vars are scalars or arrays. The shell ksh do mix both concepts into one.– user79743
Nov 29 '15 at 23:23
add a comment |
yash's array
builtin has some options that only work with array variables. Example: the -d
option will report an error on non-array variable:
$ a=123
$ array -d a
array: no such array $a
So we can do something like this:
is_array() (
array -d -- "$1"
) >/dev/null 2>&1
a=(1 2 3)
if is_array a; then
echo array
fi
b=123
if ! is_array b; then
echo not array
fi
This approach won't work if array variable is readonly. Trying to modify a readonly variable leading to an error:
$ a=()
$ readonly a
$ array -d a
array: $a is read-only
add a comment |
yash's array
builtin has some options that only work with array variables. Example: the -d
option will report an error on non-array variable:
$ a=123
$ array -d a
array: no such array $a
So we can do something like this:
is_array() (
array -d -- "$1"
) >/dev/null 2>&1
a=(1 2 3)
if is_array a; then
echo array
fi
b=123
if ! is_array b; then
echo not array
fi
This approach won't work if array variable is readonly. Trying to modify a readonly variable leading to an error:
$ a=()
$ readonly a
$ array -d a
array: $a is read-only
add a comment |
yash's array
builtin has some options that only work with array variables. Example: the -d
option will report an error on non-array variable:
$ a=123
$ array -d a
array: no such array $a
So we can do something like this:
is_array() (
array -d -- "$1"
) >/dev/null 2>&1
a=(1 2 3)
if is_array a; then
echo array
fi
b=123
if ! is_array b; then
echo not array
fi
This approach won't work if array variable is readonly. Trying to modify a readonly variable leading to an error:
$ a=()
$ readonly a
$ array -d a
array: $a is read-only
yash's array
builtin has some options that only work with array variables. Example: the -d
option will report an error on non-array variable:
$ a=123
$ array -d a
array: no such array $a
So we can do something like this:
is_array() (
array -d -- "$1"
) >/dev/null 2>&1
a=(1 2 3)
if is_array a; then
echo array
fi
b=123
if ! is_array b; then
echo not array
fi
This approach won't work if array variable is readonly. Trying to modify a readonly variable leading to an error:
$ a=()
$ readonly a
$ array -d a
array: $a is read-only
edited Nov 30 '15 at 18:19
answered Nov 30 '15 at 7:19
cuonglm
102k23201301
102k23201301
add a comment |
add a comment |
#!/bin/bash
var=BASH_SOURCE
[[ "$(declare -pa)" =~ [^[:alpha:]]$var= ]]
case "$?" in
0)
echo "$var is an array variable"
;;
1)
echo "$var is not an array variable"
;;
*)
echo "Unknown exit code"
;;
esac
add a comment |
#!/bin/bash
var=BASH_SOURCE
[[ "$(declare -pa)" =~ [^[:alpha:]]$var= ]]
case "$?" in
0)
echo "$var is an array variable"
;;
1)
echo "$var is not an array variable"
;;
*)
echo "Unknown exit code"
;;
esac
add a comment |
#!/bin/bash
var=BASH_SOURCE
[[ "$(declare -pa)" =~ [^[:alpha:]]$var= ]]
case "$?" in
0)
echo "$var is an array variable"
;;
1)
echo "$var is not an array variable"
;;
*)
echo "Unknown exit code"
;;
esac
#!/bin/bash
var=BASH_SOURCE
[[ "$(declare -pa)" =~ [^[:alpha:]]$var= ]]
case "$?" in
0)
echo "$var is an array variable"
;;
1)
echo "$var is not an array variable"
;;
*)
echo "Unknown exit code"
;;
esac
answered Dec 20 '18 at 9:56
Fólkvangr
32912
32912
add a comment |
add a comment |
Thanks for contributing an answer to Unix & Linux Stack Exchange!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Some of your past answers have not been well-received, and you're in danger of being blocked from answering.
Please pay close attention to the following guidance:
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f246026%2fcheck-variable-is-an-array-in-bourne-like-shell%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Under what circumstances would you need to check whether your variables are arrays or not?
– Kusalananda
Dec 20 '18 at 10:07