Bash: Let Statement VS Assignment

Bash: let statement vs assignment

let does exactly what (( )) do, it is for arithmetic expressions. There is almost no difference between let and (( )).

Your examples are invalid. var=${var}bar is going to add word bar to the var variable (which is a string operation), let var+=bar is not going to work, because it is not an arithmetic expression:

$ var='5'; let var+=bar; echo "$var"
5

Actually, it IS an arithmetic expression, if only variable bar was set, otherwise bar is treated as zero.

$ var='5'; bar=2; let var+=bar; echo "$var"
7

Bash assignment with let fails with /

let is a shell builtin that is a another way to use the $((..)) Arithmetic Expansion in bash. The assignment

let var2=/tmp 

is treated by the shell as an arithmetic operation "division" with an incorrect quotient value. It is equivalent to doing.

var=$((/tmp))

Since there are incorrect number of operands, the parser has thrown the error that you are seeing. Note that tmp is still treated in a variable context by the shell. If the parser had identified the expression as valid, then tmp would have undergone variable expansion. Since it is not set before, it would have likely thrown a "division-by-zero" error.

For simple variable assignments just drop the let keyword and enclose the value field within "quotes"

var2="/tmp"

bash: assignment AND condition test in nested statement?


Is this compact form generally possible in bash

No, it is not, at least not without a custom code to handle it. Command substitution is run in a subshell - changes will not be visible in parent shell. Arithmetic expansion does only arithmetic operations - all strings are converted to numbers (as if by atoi()/strtol()), if no digits are scanned they are converted to 0.

The usual way is just to assign the variable with a && followed by test - that allows to check the exit status of the command and grab the result.

if ! {
bus_connection="$(lsblk -dn -o TRAN /dev/sdd)" &&
test "$bus_connection" = "usb"
}; then
echo "not usb"
exit 1
fi

or just ignore the exit status of lsblk:

if
bus_connection="$(lsblk -dn -o TRAN /dev/sdd)"
! test "$bus_connection" = "usb"
then
echo "not usb"
exit 1
fi

Still you could write your own function that uses bash namereference to assign the first argument to the second and return with tests exit status:

test_and_assign() {
declare -n _test_and_assign_ref=$1
shift
_test_and_assign_ref="$1"
test "$@"
}

$ test_and_assign bus_connection "$(echo 123)" = "usb"
$ echo "$? $bus_connection"
1 123
$ test_and_assign bus_connection "$(echo usb)" = "usb"
$ echo "$? $bus_connection"
0 usb

Note that here, as in your first code snippet with local bus_connection=$(...), the exit status of the command substitution is ignored.

Variable assignment in command substitution

Here's man bash:

SIMPLE COMMAND EXPANSION
When a simple command is executed, the shell performs the fol‐
lowing expansions, assignments, and redirections, from left to
right.

1. The words that the parser has marked as variable
assignments (those preceding the command name) and
redirections are saved for later processing.

2. The words that are not variable assignments or redirec‐
tions are expanded. If any words remain after expan‐
sion, the first word is taken to be the name of the
command and the remaining words are the arguments.
[...]

In your case, the simple command has a single word $(echo var=foo).

Since there are no words marked as variable assignments (because this word is instead a command substitution), step 1 doesn't apply.

We then move on to step 2, where the word $(echo var=foo) is expanded into var=foo. We don't go back to the first step, we just do what step 2 says: "take the first word as the name of the command".

This is why var=foo is executed as a command instead of being interpreted as an assignment.

Shell Script : shortcut add and assignment += : command not found

Your syntax for incrementing the variable is correct, but you are using it in a context where Bash wants a command, and it complains that the result of the increment (4) is not a recognized command.

The let keyword is your friend.

let SumVar+=4

Or better yet just leave out the dollar sign (thanks @chepner);

(( SumVar += 4 ))

How to build a conditional assignment in bash?

As per Jonathan's comment:

variable=$(( 1 == 1 ? 1 : 0 ))  

EDIT:

I revised the original answer which just echo'd the value of the condition operator, it didn't actually show any assignment.



Related Topics



Leave a reply



Submit