Variable with quotation marks "$()"
Quotation marks prevent "word splitting". That is: breaking down variables into multiple items at whitespace characters (or to be more exact, at spaces, tabs, and newlines as defined in the value of the default $IFS
shell variable).
For example,
$ var="one two"
$ howmany(){ echo $#; }
$ howmany $var
2
$ howmany "$var"
1
Here we define the howmany
function which just lets us know how many positional parameters are given. As you can see, there are two items being passed to the variable, and with the quotes the text in the variable is treated as one unit.
This is important for accurate passing of information. For example, if the variable contains path to file, and the filename contains spaces anywhere in the path, the command you are trying to run may fail or give inaccurate results. If we were trying to create a file with the $var
variable, touch $var
would create two files, but touch "$var"
just one.
Same goes for your [ "$currentoutput" != "$lastoutput" ]
part. This particular test performs a comparison on two strings. When the test runs, the [
command would need to see 3 arguments - a text string, the !=
operator, and another text string. Keeping double quotes prevents word splitting, and the [
command sees exactly those 3 arguments. Now what happens if variables are unquoted ?
$ var="hello world"
$ foo="hi world"
$ [ $var != $foo ]
bash: [: too many arguments
$
Here, word splitting occurs, and instead [
sees two strings hello
and world
followed by !=
, followed by two other strings hi world
. Key point is that without double quotes, the contents of variables are understood as separate units rather than one whole item.
Assigning command substitution doesn't require double quotes as in
var=$( df )
where you have the df
command's output saved to var
. However, it is a good habit to always double quote variables and command substitution $(...)
unless you do in fact want the output to be treated as separate items.
On a side note, the
while [ true ]
part can be
while true
[
is a command which evaluates its arguments, and [ whatever ]
is always true regardless of what is inside. By contrast, while true
uses the command true
which always returns success exit status (and that's exactly what while
loop needs). The difference is a bit more clarity and less testing performed. Alternatively, you could also use :
instead of true
The double quotes in echo "" date and Time
part could probably be removed. They merely insert an empty string and an add extra space to the output. If that's desired, feel free to keep them there, but there's no particular functional value in this case.
lsusb >> test.log
This part could probably be replaced with echo "$currentoutput" >> test.log
. There's no reason to run lsusb
again after it has been run already in currentoutput=$(lsusb)
. In cases where trailing newlines
have to be preserved in the output - one could see the value in running a command multiple times, but in case of lsusb
there's no need for that. The less external commands you call, the better, because every call to a non-built-in command incurs costs in CPU, memory usage, and execution time ( even though the commands are probably pre-loaded from memory).
See also:
- When is double-quoting necessary?
- What is the point of the bash null operator : (colon)?
- Security implications of forgetting to quote a variable in bash/POSIX shells
The following runs the external command command
and returns its output.
"$(command)"
Without the brackets/parentheses, this would look for a variable instead of running a command:
"$variable"
As for the difference between $variable
and "$variable"
, this becomes relevant when $variable
contains spaces. When using "$variable"
, the entire variable contents will be inserted into a single string even if the contents include spaces. When using $variable
the contents of the variable may be expanded into an argument list of multiple arguments.
In currentoutput="$(lsusb)"
lsusb is not a variable, it is a command. What this statement does, it executes lsusb
command and assigns its output to currentoutput
variable.
Older syntax for this was
currentoutput=`lsusb`
you can find it in many examples and scripts
To answer the other part of your question, if [ ]
is just how syntax for if
is defined in bash. See more in https://www.tldp.org/LDP/Bash-Beginners-Guide/html/sect_07_01.html