Check variable is an array in Bourne like shell?
Solution 1
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.
Solution 2
In zsh
zsh% a=(1 2 3) s=1
zsh% [[ ${(t)a} == *array* ]] && echo array
array
zsh% [[ ${(t)s} == *array* ]] && echo array
zsh%
Solution 3
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
Solution 4
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
)
Solution 5
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
Related videos on Youtube
user3717775
Updated on September 18, 2022Comments
-
user3717775 over 1 year
I am trying to upload an image file with the code below, but the file is not being uploaded. The console still shows the message "1 Record Successfully Inserted."
Create table image ( name varchar2(20), photo blob ); import java.sql.*; import java.io.*; public class ImageWriter { static Connection connection = null; static CallableStatement pstat = null; static String connectionURL = null; public static void main(String[] args) { try{ Class.forName("oracle.jdbc.driver.OracleDriver"); connection = DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:xe", "SYSTEM", "SYSTEM"); PreparedStatement pstat = connection.prepareStatement("insert into image(name,photo) values(?,?)"); FileInputStream fin = new FileInputStream("E:\\test.jpg"); pstat.setString(1, "ABC"); pstat.setBinaryStream(2, fin,fin.available()); int result = pstat.executeUpdate(); System.out.println(result + " Record Successfully Inserted"); connection.close(); } catch(Exception e){ e.printStackTrace(); } } }
-
Raptor almost 10 yearswhy do you want to save an image into DB? You can just save the image path and leave the image file in server...
-
sunleo almost 10 yearsYou have done insertion then whats wrong.?
-
user3717775 almost 10 yearsinsertion is done only for name field not for photo field.As I am seeing data in database for photo, it shows data not available.
-
Robby Cornelissen almost 10 yearsDo you get the same problem if you just do
pstat.setBinaryStream(2, fin);
, i.e. without thefin.available()
?
-
-
cuonglm over 8 yearsSo I guess checking if
${a[1]-not array}
can do the task, can't it? -
mikeserv over 8 years@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 doa[5]=x
. I guess[ 1 -eq "${#a[@]}" ] && [ -n "${a[0]+1}" ]
could work. -
PSkocik over 8 years@mikeserv Good point. Aliases make it look prettier. +1
-
mikeserv over 8 yearsi 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. -
PSkocik over 8 years@mikeserv I'm sure cuonglm is well capable of tweaking this approach to his needs and preferences. ;-)
-
PSkocik over 8 years... and security considerations.
-
mikeserv over 8 yearswell, true, and it didn't matter when you just used
eval
, because you only targeted the one definition, but when youalias x='eval "$x"'
it may not be immediately apparent to some that thealias
and$x
are connected over time. you know what I mean? i mean that a lot of people may think thealias
definition sticks even if the variable doesn't - that's all i'm getting at... but you can't portably make functionsreadonly
, and i've only now learned you can at all... -
Admin over 8 yearsThe
typeset +a
also reports an error in ksh. Not in zsh, though. -
Admin over 8 yearsMaybe
echo ${(t)var}
is simpler. Thanks for this. -
Admin over 8 yearsTry:
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.