Skip to main content
add link to post that I've written and that references this page
Source Link
qmacro
  • 143
  • 7

Update 03 Sep : Here's the blog post where I've written up what I've learned so far from reading through fff, and I've referenced this question and the great answers in it too: Exploring fff part 1 - main.

Update 03 Sep : Here's the blog post where I've written up what I've learned so far from reading through fff, and I've referenced this question and the great answers in it too: Exploring fff part 1 - main.

Became Hot Network Question
Add relevant tag
Link
AdminBee
  • 23.6k
  • 25
  • 55
  • 77
Source Link
qmacro
  • 143
  • 7

Bash's read builtin errors on a string-based timeout option specification but not an array-based one. Why?

In reading through the source to fff to learn more about Bash programming, I saw a timeout option passed to read as an array here:

read "${read_flags[@]}" -srn 1 && key "$REPLY"

The value of read_flags is set like this:

read_flags=(-t 0.05)

(The resulting read invocation intended is therefore read -t 0.05 -srn 1).

I can't quite figure out why a string could not have been used, i.e.:

read_flags="-t 0.05"
read "$read_flags" -srn 1 && key "$REPLY"

This string based approach results in an "invalid timeout specification".

Investigating, I came up with a test script parmtest:

show() {
  for i in "$@"; do printf '[%s]' "$i"; done
  printf '\n'
}

opt_string="-t 1"
opt_array=(-t 1)

echo 'Using string-based option...'
show string "$opt_string" x y z
read "$opt_string"
echo
echo 'Using array-based option...'
show array "${opt_array[@]}" x y z
read "${opt_array[@]}"

Running this, with bash parmtest ($BASH_VERSION is 5.1.4(1)-release), gives:

Using string-based option...
[string][-t 1][x][y][z]
parmtest: line 11: read:  1: invalid timeout specification

Using array-based option...
[array][-t][1][x][y][z]
(1 second delay...)

I can see from the debug output that the value of 1 in the array based approach is separate and without whitespace. I can also see from the error message that there's an extra space before the 1: read: 1: invalid timeout specification. My suspicions are in that area.

The strange thing is that if I use this approach with another command, e.g. date, the problem doesn't exist:

show() {
  for i in "$@"; do printf '[%s]' "$i"; done
  printf '\n'
}

opt_string="-d 1"
opt_array=(-d 1)

echo 'Using string-based option...'
show string "$opt_string" x y z
date "$opt_string"
echo
echo 'Using array-based option...'
show array "${opt_array[@]}" x y z
date "${opt_array[@]}"

(The only differences are the opt_string and opt_array now specify -d not -t and I'm calling date not read in each case).

When run with bash parmtest this produces:

Using string-based option...
[string][-d 1][x][y][z]
Wed Sep  1 01:00:00 UTC 2021

Using array-based option...
[array][-d][1][x][y][z]
Wed Sep  1 01:00:00 UTC 2021

No error.

I've searched, but in vain, to find an answer to this. Moreover, the author wrote this bit directly in one go and used an array immediately, which makes me wonder.

Thank you in advance.