Skip to main content
added 211 characters in body
Source Link
ilkkachu
  • 147.9k
  • 16
  • 268
  • 441
read_flags="-t 0.05"
read "$read_flags" -srn 1

Here, "$read_flags" is in double quotes, so it's not wordsplit. As you saw, the result is the same as running

read "-t 0.05" -srn 1

which means the specified timeout indeed has a leading space. Now, apparently whatever Bash does to parse the number doesn't like that.

What the extra space does, depends totally on the program. When parsing a number, it should be easy enough to ignore any leading white space, and the standard strtod() function does just that. With date -d, it has to parse a more complex string, so it's not surprising it's not strict about whitespace. (It could be something like 12:00 Jun 4 2019 UTC + 5 days and not just a single number.) Hard to say why Bash is so picky here.

Now, if you were passing a filename, a string with a leading space would be a different onefilename than the one without, and it'd be hard for any program to know to ignore it.


With such simple values (andwithout glob characters and where you want to split on each run of whitespace, assuming the default IFS), you could indeed youuse a string instead of an array, you just need to not quote it, so that it is split into two distinct arguments. So, read $read_flags .... Or just set timeoutflag=-t0.05 and then read "$timeoutflag" .... Though note that read "$timeoutflag" isn't optimal in that if the variable is empty, it will get passed as a distinct empty argument, giving an error.

In general, arrays are the correct way to store and use arbitrary lists of arguments. With a single string, you'd e.g. have problems if you need to pass e.g. filenames with spaces without issues.

Somewhat related: How can we run a command stored in a variable?

read_flags="-t 0.05"
read "$read_flags" -srn 1

Here, "$read_flags" is in double quotes, so it's not wordsplit. As you saw, the result is the same as running

read "-t 0.05" -srn 1

which means the specified timeout indeed has a leading space. Now, apparently whatever Bash does to parse the number doesn't like that.

What the extra space does, depends totally on the program. When parsing a number, it should be easy enough to ignore any leading white space, and the standard strtod() function does just that. With date -d, it has to parse a more complex string, so it's not surprising it's not strict about whitespace. (It could be something like 12:00 Jun 4 2019 UTC + 5 days and not just a single number.)

Now, if you were passing a filename, a string with a leading space would be a different one than the one without, and it'd be hard for any program to know to ignore it.


With such simple values (and the default IFS), you could indeed you a string instead of an array, you just need to not quote it, so that it is split into two distinct arguments. So, read $read_flags .... Or just set timeoutflag=-t0.05 and then read "$timeoutflag" ....

In general, arrays are the correct way to store arbitrary lists arguments. With a single string, you'd e.g. have problems if you need to pass e.g. filenames with spaces.

Somewhat related: How can we run a command stored in a variable?

read_flags="-t 0.05"
read "$read_flags" -srn 1

Here, "$read_flags" is in double quotes, so it's not wordsplit. As you saw, the result is the same as running

read "-t 0.05" -srn 1

which means the specified timeout indeed has a leading space. Now, apparently whatever Bash does to parse the number doesn't like that.

What the extra space does, depends totally on the program. When parsing a number, it should be easy enough to ignore any leading white space, and the standard strtod() function does just that. With date -d, it has to parse a more complex string, so it's not surprising it's not strict about whitespace. (It could be something like 12:00 Jun 4 2019 UTC + 5 days and not just a single number.) Hard to say why Bash is so picky here.

Now, if you were passing a filename, a string with a leading space would be a different filename than the one without, and it'd be hard for any program to know to ignore it.


With such simple values (without glob characters and where you want to split on each run of whitespace, assuming the default IFS), you could indeed use a string instead of an array, you just need to not quote it, so that it is split into two distinct arguments. So, read $read_flags .... Or just set timeoutflag=-t0.05 and then read "$timeoutflag" .... Though note that read "$timeoutflag" isn't optimal in that if the variable is empty, it will get passed as a distinct empty argument, giving an error.

In general, arrays are the correct way to store and use arbitrary lists of arguments without issues.

Somewhat related: How can we run a command stored in a variable?

Source Link
ilkkachu
  • 147.9k
  • 16
  • 268
  • 441

read_flags="-t 0.05"
read "$read_flags" -srn 1

Here, "$read_flags" is in double quotes, so it's not wordsplit. As you saw, the result is the same as running

read "-t 0.05" -srn 1

which means the specified timeout indeed has a leading space. Now, apparently whatever Bash does to parse the number doesn't like that.

What the extra space does, depends totally on the program. When parsing a number, it should be easy enough to ignore any leading white space, and the standard strtod() function does just that. With date -d, it has to parse a more complex string, so it's not surprising it's not strict about whitespace. (It could be something like 12:00 Jun 4 2019 UTC + 5 days and not just a single number.)

Now, if you were passing a filename, a string with a leading space would be a different one than the one without, and it'd be hard for any program to know to ignore it.


With such simple values (and the default IFS), you could indeed you a string instead of an array, you just need to not quote it, so that it is split into two distinct arguments. So, read $read_flags .... Or just set timeoutflag=-t0.05 and then read "$timeoutflag" ....

In general, arrays are the correct way to store arbitrary lists arguments. With a single string, you'd e.g. have problems if you need to pass e.g. filenames with spaces.

Somewhat related: How can we run a command stored in a variable?