I get an error in my Bash shell script script.sh on this line of code:
let initialLines=$(grep '' "1ドル" | wc -l || true)
error is: script.sh: line 146: let: initialLines=: syntax error: operand expected (error token is "=")
What is syntactically incorrect here?
2 Answers 2
tl;dr:
Double-quote your command substitution:
let initialLines="$(grep '' "1ドル" | wc -l || true)"
That said, as explained in chepner's helpful answer, you could just use a simple assignment without needing to double-quote the RHS, although to get the same outcome as with let
here, be sure to declare the variable with -i
first; e.g., declare -i initialLines
It looks like the RHS of your assignment - the command substitution ($(...)
) - evaluates either to the empty string or a whitespace-prefixed string in the course of the shell expansions that happen before the command is executed, so that bash
ends up trying to parse one of the following commands:
let initialLines=
let initialLines= 2
If you try these in isolation, you'll get the syntax error you've experienced.
The most likely explanation is that you're using BSD wc
, such as on macOS, which outputs the line count requested with -l
with leading whitespace.
A simple fix is to double-quote the command substitution:
let initialLines="$(grep '' "1ドル" | wc -l || true)"
As for the command in your command substitution (it may just be an example, but it's worth commenting on):
grep ''
will always return all input lines, so it's nothing more than a less efficientcat
.There is no point in using
|| true
:The exit code of the subshell in which the command substitution runs is not relevant, even with
set -e
in effect.Also, by using
true
as the alternative command, you'll break thelet
command as well, because builtintrue
has no stdout output.
In summary, your entire command substitution could be reduced to
wc -l < "1ドル"
.
-
1Yes this did get rid of the error and I am using macOS so very knowledgeable answerChisx– Chisx2017年01月23日 03:33:31 +00:00Commented Jan 23, 2017 at 3:33
There is little or no need to use the let
command here.
initialLines=$(grep '' "1ドル" | wc -l)
This solves the problem (the command substitution producing an empty or white-space prefixed string) pointed out by @mklement0 in a different way; unlike the argument to the let
command, the value on the right-hand side of an assignment is not subject to word-splitting.
-
While good advice in general, there is a subtlety to consider here: to really make the two commands equivalent, you must declare
initialLines
with-i
first, otherwise justinitialLines=$(grep '' "1ドル" | wc -l)
will retain leading whitespace, such as the one output bywc -l
on macOS.mklement0– mklement02017年01月23日 03:20:15 +00:00Commented Jan 23, 2017 at 3:20
grep
command is equivalent tocat "1ドル"
, in which case you could simply runwc -l "1ドル"
.wc -l < "1ドル"
(note the<
), so as to preventwc
from outputting the input filename as well.grep -c
could be used instead as well.)