While you can transform this file to be a shell snippet, it's tricky. You need to make sure that all shell special characters are properly quoted.
The easiest way to do that is to put single quotes around the value and replace single quotes inside the value by '\''
. You can then put the result into a temporary file and source that file.
script=$(mktemp)
sed <"config-file" >"$script" \
-e '/^[A-Z_a-z][A-Z_a-z]*=/ !d' \
-e s/\'/\'\\\\\'\'/g \
-e s/=/=\'/ -e s/\$/\'/
I recommend doing the parsing directly in the shell instead. The complexity of the code is about the same, but there are two major benefits: you avoid the need for a temporary file, and the risk that you accidentally got the quoting wrong and end up executing a part of a line as a shell snippet (something like dangerous='$(run me)'
). You also get a better chance at validating potential errors.
while IFS= read -r line; do
line=${line%%#*} # strip comment (if any)
case $line in
*=*)
var=${line%%=*}
case $var in
*[!A-Z_a-z]*)
echo "Warning: invalid variable name $var ignored" >&2
continue;;
esac
if eval '[ -n "${'$var'+1}" ]'; then
echo "Warning: variable $var already set, redefinition ignored" >&2
continue
fi
line=${line#*=}
eval $var='"$line"'
esac
done <"config-file"
So between 2^63 and 2^64-1, you get negative integers showing you how far off from ULONG_MAX you are.
No. How do you figure that? By your own example, the max is:
> max=$((2**63 - 1)); echo $max
9223372036854775807
If "overflow" meant "you get negative integers showing you how far off from ULONG_MAX you are", then if we add one to that, shouldn't we get -1? But instead:
> echo $(($max + 1))
-9223372036854775808
Perhaps you mean this is a number you can add to $max
to get a negative difference, since:
> echo $(($max + 1 + $max))
-1
But this does not in fact continue to hold true:
> echo $(($max + 2 + $max))
0
This is because the system uses two's complement to implement signed integers.1 The value resulting from an overflow is NOT an attempt to provide you with a difference, a negative difference, etc. It is literally the result of truncating a value to a limited number of bits, then having it interpreted as a two's complement signed integer. For example, the reason $(($max + 1 + $max))
comes out as -1 is because the highest value in two's complement is all bits set except the highest bit (which indicates negative); adding these together basically means carrying all the bits to the left so you end up with (if the size were 16-bits, and not 64):
11111111 11111110
The high (sign) bit is now set because it carried over in the addition. If you add one more (00000000 00000001) to that, you then have all bits set, which in two's complement is -1.
I think that partially answers the second half of your first question -- "Why are the negative integers...exposed to the end user?". First, because that is the correct value according to the rules of 64-bit two's complement numbers. This is the conventional practice of most (other) general purpose high level programming languages (I cannot think of one that does not do this), so bash
is adhering to convention. Which is also the answer to the first part of the first question -- "What's the rationale?": this is the norm in the specification of programming languages.
WRT the 2nd question, I have not heard of systems which interactively change ULONG_MAX.
If someone arbitrarily changes the value of the unsigned integer maximum in limits.h, then recompiles bash, what can we expect will happen?
It would not make any difference to how the arithmetic comes out, because this is not an arbitrary value that is used to configure the system -- it's a convenience value that stores an immutable constant reflecting the hardware. By analogy, you could redefine c to be 55 mph, but the speed of light will still be 186,000 miles per second. c is not a number used to configure the universe -- it's a deduction about the nature of the universe.
ULONG_MAX is exactly the same. It is deduced/calculated based on the nature of N-bit numbers. Changing it in limits.h
would be a very bad idea if that constant is used somewhere assuming it is supposed to represent the reality of the system.
And you cannot change the reality imposed by your hardware.
1. I don't think that this (the means of integer representation) is actually guaranteed by bash
, since it depends on the underlying C library and standard C does not guarantee that. However, this is what is used on most normal modern computers.
Best Answer
bash
does not understand floating point numbers.Quoting
bash
manual page, section ARITHMETIC EVALUATION:So
((3 < 4))
or((3 < 2))
are actually correct arithmetic expressions. You can type the following:But
$ echo $((3.3 < 3.6))
will return a syntax error message. In your example, you are actually comparing strings. Hence some example: