Home > OS >  How do bash variable types work and how to work around automatic interpretation?
How do bash variable types work and how to work around automatic interpretation?

Time:10-24

I am trying to set up a variable that contains a string representation of a value with leading zeroes. I know I can printf to terminal the value, and I can pass the string output of printf to a variable. It seems however that assigning the value string to a new variable reinterprets the value and if I then print it, the value has lost its leading zeroes.

How do we work with variables in bash scripts to avoid implicit type inferences and ultimately how do I get to the solution I'm looking for. FYI I'm looking to concatenate a large fixed length string numeric, something like a part number, and build it from smaller prepared strings.

Update:

Turns out exactly how variables are assigned changes their interpretation in some way, see below:

Example:

#!/bin/bash
a=3
b=4
aStr=$(printf d $a)
bStr=$(printf d $b)

echo $aStr$bStr

output

$ ./test.sh
003004
$

Alternate form:

#!/bin/bash
((a = 3))
((b = 4))
((aStr = $(printf d $a)))
((bStr = $(printf d $b)))

echo $aStr$bStr

output

$ ./test.sh
34
$

CodePudding user response:

By doing ((aStr = $(printf d $a))), you are destroying again the careful formatting done by printf. You would see the same effect if you do a

(( x = 005 ))
echo $x

which outputs 5.

Actually the zeroes inserted by printf could do harm to your number, as you see by the following example:

(( x = 015 ))
echo $x

which outputs 13, because the ((....)) interprets the leading zero as an indication for octal numbers.

Hence, if you have a string representing a formatted (pretty-printed) number, don't use this string in numeric context anymore.

CodePudding user response:

How do bash variable types

There are no variable types. All variables are strings (type).. Variables store a value (a string), but also variables have some additional magic attributes associated with them.

There are Bash arrays, but I think it's an attribute that a variable is an array. Still, in any case, every array element holds a string. There is a "numeric" variable declare -i var, but it's attribute of the variable - in memory, the variable is still a string, only when setting it Bash checks if the string (still a string!) to be set is a number.

assigning the value string to a new variable reinterprets the value

Bash does not "interpret" the value on assignment.

How do we work with variables in bash scripts to avoid implicit type inferences

There are no "type inferences". The type of variable does not change - it holds a string.

The value of the variable undergoes different expansions and conversions depending on the context where it is used. For example $(...) removes trailing newlines. Most notably unquoted variable expansions undergo word splitting and filename expansion.

Example:

Posting your code to shellcheck results in:

Line 2:
a = 3
  ^-- SC2283 (error): Remove spaces around = to assign (or use [ ] to compare, or quote '=' if literal).
 
Line 3:
b = 4
  ^-- SC2283 (error): Remove spaces around = to assign (or use [ ] to compare, or quote '=' if literal).
 
Line 4:
aStr = $(printf d $a)
     ^-- SC2283 (error): Remove spaces around = to assign (or use [ ] to compare, or quote '=' if literal).
       ^-- SC2046 (warning): Quote this to prevent word splitting.
                     ^-- SC2154 (warning): a is referenced but not assigned.
                     ^-- SC2086 (info): Double quote to prevent globbing and word splitting.

Did you mean: (apply this, apply all SC2086)
aStr = $(printf d "$a")
 
Line 5:
bStr = $(printf d $b)
     ^-- SC2283 (error): Remove spaces around = to assign (or use [ ] to compare, or quote '=' if literal).
       ^-- SC2046 (warning): Quote this to prevent word splitting.
                     ^-- SC2154 (warning): b is referenced but not assigned.
                     ^-- SC2086 (info): Double quote to prevent globbing and word splitting.

Did you mean: (apply this, apply all SC2086)
bStr = $(printf d "$b")
 
Line 7:
echo $aStr$bStr
     ^-- SC2154 (warning): aStr is referenced but not assigned.
     ^-- SC2086 (info): Double quote to prevent globbing and word splitting.
          ^-- SC2154 (warning): bStr is referenced but not assigned.
          ^-- SC2086 (info): Double quote to prevent globbing and word splitting.

Did you mean: (apply this, apply all SC2086)
echo "$aStr""$bStr"

Shellcheck tells you what is wrong. After fixing the problems:

#!/bin/bash
a=3
b=4
aStr=$(printf d "$a")
bStr=$(printf d "$b")

echo "$aStr$bStr"

Which upon execution outputs your expected output:

003004
  • Related