6

I am working with: s3-bash, when I run it in my local environment (OS X 10.10.1) I don't have any problems, when I try to run it on a ubuntu server 14.04.1 I get the following error:

./s3-common-functions: line 66: temporaryFiles: unbound variable
./s3-common-functions: line 85: temporaryFiles: unbound variable

I've looked at the s3-common-functions script and the variable looks to be initialized properly (as an array):

# Globals
declare -a temporaryFiles

But there is a note in the comment, and I'm sure if it's related:

# Do not use this from directly. Due to a bug in bash, array assignments do not work when the function is used with command substitution
function createTemporaryFile
{
    local temporaryFile="$(mktemp "$temporaryDirectory/$$.$1.XXXXXXXX")" || printErrorHelpAndExit "Environment Error: Could not create a temporary file. Please check you /tmp folder permissions allow files and folders to be created and disc space." $invalidEnvironmentExitCode
    local length="${#temporaryFiles[@]}"
    temporaryFiles[$length]="$temporaryFile"
}
6
  • 1
    unbound variable is what you get when using set -u. Do you have that set in whatever environment you are running the script? Commented Jan 20, 2015 at 21:23
  • 1
    What's the command you run that causes this error? Commented Jan 20, 2015 at 21:28
  • 2
    Bug? What's described in the comment text is not a bug, but normal and expected behavior. foo=$(bar) runs bar in a subshell, so of course assignments done inside that subshell don't propagate to the parent shell. Commented Jan 20, 2015 at 22:19
  • 2
    (I wonder how old of a bash interpreter s3-bash tries to support; that particular method for appending to an array hasn't been necessary for rather a while, the new syntax being temporaryFiles+=( "$temporaryFile" )... though, of course, that doesn't change anything about propagation of variables from subshells to parents). Commented Jan 20, 2015 at 22:21
  • @EtanReisner looking at the source set -u is called a few lines above as well as set -e, I'm not an expert in bash so I'm not sure the effect, but I shouldn't have to set any env. variables to run the script (I don't believe). It also appears to fail when reading the array length local length="${#temporaryFiles[@]}" & length="${#temporaryFiles[@]}" Commented Jan 21, 2015 at 1:35

4 Answers 4

12

There appears to be a bash behaviour change at play here.

Found by kojiro: CHANGES

hhhh. Fixed a bug that caused `declare' and `test' to find variables that had been given attributes but not assigned values. Such variables are not set.

$ bash --version
GNU bash, version 3.2.25(1)-release (x86_64-redhat-linux-gnu)
Copyright (C) 2005 Free Software Foundation, Inc.
$ set -u
$ declare -a tF
$ echo "${#tF[@]}"
0

vs.

$ bash --version
GNU bash, version 4.1.2(1)-release (x86_64-redhat-linux-gnu)
Copyright (C) 2009 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>

This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
$ set -u
$ declare -a tF
$ echo "${#tF[@]}"
0

vs.

$ bash --version
GNU bash, version 4.3.30(1)-release (x86_64-pc-linux-gnu)
Copyright (C) 2013 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>

This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
$ set -u
$ declare -a tF
$ echo "${#tF[@]}"
-bash: tF: unbound variable

You can use declare -a tF=() on the newer bash versions to work around this.

$ declare -a tF=()
$ echo "${#tF[@]}"
0
Sign up to request clarification or add additional context in comments.

3 Comments

Changed between bash-4.2-release and bash-4.3-alpha: hhhh. Fixed a bug that caused `declare' and `test' to find variables that had been given attributes but not assigned values. Such variables are not set. – (sorry txt doesn't allow more precise linking, but you can search for the exact text if you like.)
@kojiro Thanks for finding that.
In BASH 4.3 (bash-4.3-83.33.1.x86_64 of SLES 12 SP5 declare -a a=() still(?) causes an unbound variable for "${a[@]}".
5

Bash can substitute an empty value into unset variables using a dash.

set -u
my_array=()
printf "${my_array[@]-}\n"

This specific example will print nothing, but it will not give you an unbound variable error either.

Stolen from Bash: Error `Unbound variable' when appending to empty array1.

However, when used for a loop, you get one iteration (not zero) then:

for i in "${my_array[@]-}"
do
    echo $i
done

Expectation might be to get zero iterations.

It could be fixed this way then:

[ ${#my_array[@]} -gt 0 ] &&
for i in "${my_array[@]}"
do
    echo $i
done

2 Comments

That will not work when trying to find the size. I.e. ${#my_array[@]-} will generate a bad substitution error.
This solved it for me, since my Centos 7.7 host is running Bash 4.2.46(2), which otherwise has an error if I try to iterate over an empty array.
0

Changed declaration of array for temporaryfiles

declare -a temporaryFiles

to:

temporaryFiles=()

Why this is different / non-function in ubuntu 14.04.1 Linux 3.13.0-32-generic x86_64 versus OS X I am not sure ?

Comments

0
find $fullfolder -type f |
while read fullfile
do
    filename=$(basename "$fullfile")
    ext=$([[ $filename = *.* ]] && printf %s ${filename##*.} || printf 'NONE')
    arr+=($ext)
    echo ${#arr[@]}
done
echo ${#arr[@]}

Why does the ${#arr[@]} inside the for loop produce the correct result but the one outside gives 0?

1 Comment

You pipe! ("'Each command in a pipeline is executed as a separate process (i.e., in a subshell).*" And don't ask questions in answers! Maybe see unix.stackexchange.com/q/9954/320598 and similars...

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.