I try to run bash scripts in Docker, buit I keep getting this error:
./scripts/proto-generator.sh: line 13: syntax error: unexpected "(" (expecting "then")
Here's my proto-generator.sh file:
function printGreen() {
printf "\e[0;32m$1\e[0;m\n"
}
function printRed() {
printf "\e[0;31m$1\e[0;m\n"
}
service=$1
outDir=./src/services/$service/models
protoDir=./protos/"${service}Service"/*.proto
if ! [[ "$service" =~ ^(file|user)$ ]]; then
printRed "Incorrect service: $service"
exit 1
fi
./node_modules/.bin/proto-loader-gen-types \
--longs=String \
--enums=String \
--defaults \
--oneofs \
--grpcLib=#grpc/grpc-js \
--outDir=$outDir \
$protoDir
printGreen "GRPC codes generated: ${outDir}"
How can I fix the syntax error?
Thanks for any help!!
I would have loved to ask that question as a comment, but I'm not allowed to, yet. Anyway, after having had a quick test, I assume your docker image is Alpine Linux-based. The standard Alpine Linux docker images do not come with a bash as you might be expecting but with an ash and ash does not have a [[-built in command, i.e. you should be sticking to the standard [ aka test command or get goind completely without it. And, sadly enough, test does not have the ability to handle regular expressions.
That said and again assuming that you do not want to bloat the Alpine image with a complete bash, grep comes to the rescue. A solution for your case would be (lines 13, ff.)
if ! echo $service | grep -qE "^(file|user)$" ; then
printRed "Incorrect service: $service"
exit 1
fi
explanation
Make the if directly test the return code from grep using your pattern. grep returns non-zero if there was no match, 0 otherwise. -q suppresses output of the match, -E switches to extended regular expression, as needed for the |.
Just put a
#!/bin/bash
at the top of the script
I think you are executing it in /bin/sh,
and sh doesn't support bash regex.
Or you are using an outdated version of bash, regex in bash where introduced recently.
Related
I have a bash script (test.sh) with the following:
#!/bin/bash
npm test |& grep -v '[HPM]'
if [[ $? -ne 0 ]]; then
...
When trying to run this script locally I get this error:
test.sh: line 3: syntax error near unexpected token `&'
test.sh: line 3: `npm test |& grep -v '[HPM]''
The |& syntax is using a non-standard token which is recognized by bash but not all shells. Such a construct is often called a bashism. If your shell is inadvertently invoked as a non-bash shell, then it is a syntax error. You can easily use a standardized construct for this:
npm test 2>&1 | grep -v '\[HPM\]'
Note that this is unusual. It seems odd to capture the stderr of npm, but perhaps you really do want to check if grep prints any lines. There's really no need to explicitly check $?, and your code would normally be written:
if ! npm test 2>&1 | grep -v '\[HPM\]'; then
: grep failed. Do something
fi
But again, this seems strange. grep -v will "fail" if it does not print any lines of text, and it will succeed otherwise. Perhaps you were expecting $? to contain the exit status of npm in your original code, but it does not. $? will be zero if grep prints any text, and non-zero otherwise.
Example script:
#!/bin/bash
printf '1\n1\n1\n1\n' | ./script2*.sh >/dev/null 2>/dev/null
Shellcheck returns the following:
In script1.sh line 3:
printf '1\n1\n1\n1\n' | ./script2*.sh >/dev/null 2>/dev/null
^-- SC2211: This is a glob used as a command name. Was it supposed to be in ${..}, array, or is it missing quoting?
According to https://github.com/koalaman/shellcheck/wiki/SC2211, there should be no exceptions to this rule.
Specifically, it suggests "If you want to specify a command name via glob, e.g. to not hard code version in ./myprogram-*/foo, expand to array or parameters first to allow handling the cases of 0 or 2+ matches."
The reason I'm using the glob in the first place is that I append or change the date to any script that I have just created or changed. Interestingly enough, when I use "bash script2*.sh" instead of "./script2*.sh" the complaint goes away.
Have I fixed the problem or I am tricking shellcheck into ignoring a problem that should not be ignored? If I am using bad bash syntax, how might I execute another script that needs to be referenced to using a glob the proper way?
The problem with this is that ./script2*.sh may end up running
./script2-20171225.sh ./script2-20180226.sh ./script2-copy.sh
which is a strange and probably unintentional thing to do, especially if the script is confused by such arguments, or if you wanted your most up-to-date file to be used. Your "fix" has the same fundamental problem.
The suggestion you mention would take the form:
array=(./script2*.sh)
[ "${#array[#]}" -ne 1 ] && { echo "Multiple matches" >&2; exit 1; }
"${array[0]}"
and guard against this problem.
Since you appear to assume that you'll only ever have exactly one matching file to be invoked without parameters, you can turn this into a function:
runByGlob() {
if (( $# != 1 ))
then
echo "Expected exactly 1 match but found $#: $*" >&2
exit 1
elif command -v "$1" > /dev/null 2>&1
then
"$1"
else
echo "Glob is not a valid command: $*" >&2
exit 1
fi
}
whatever | runByGlob ./script2*.sh
Now if you ever have zero or multiple matching files, it will abort with an error instead of potentially running the wrong file with strange arguments.
I am running bash script that needs to run different code for SunOs and Linux and I am getting the syntax error from the part of the code that not supposed to be true. I did not expect that since I thought that Bash works as interpreter.
The bash version on SunOS is 2.5 and on Linux is 4.1. The syntax it complains about is only supported from 3.1 version.
I tried to disable the newer code with "else" clause but it looks like it still pre-parses.
Also my script has ":" instead of "#! /bin/sh" as first line.
test.sh:
:
echo "`uname`"
if [ `uname` = "SunOS" ]
then
echo "do old stuff"
else
echo "new stuff"
arr=($(grep "^X1" ../foo.txt | sed 's/.*=//'))
fi
The error is
> ./test.sh
SunOS
./test.sh: syntax error at line 8: `arr=' unexpected
If I comment error line then it will work fine:
:
echo "`uname`"
if [ `uname` = "SunOS" ]
then
echo "do old stuff"
else
echo "new stuff"
#arr=($(grep "^X1" ../foo.txt | sed 's/.*=//'))
fi
The result is
> ./test.sh
SunOS
do old stuff
My question is how do I fix this syntax error without commenting? I have to have "if/else" to be able to run this script on different machines.
That array syntax has been supported in bash since at least version 2; if you're getting errors there, it's because your script is not running under bash at all, but under some other shell. This probably has a lot to do with your script starting with : instead of a shebang line, meaning it's up to whatever runs the script to figure out what to run it with, with inconsistent results. I'd strongly recommend using a proper shebang line. If bash doesn't exist in a predictable location, you could use #!/usr/bin/env bash. If bash might not be in the PATH, you could use something like the script prologue here -- a #!/bin/sh shebang followed by commands to find and switch to bash.
As for the question about pre-parsing: yes, bash and other shells will parse all the way to the fi keyword before executing the if construct. They need to find the then, else, and fi keywords in order to figure out what they're going to execute and what they're going to skip, and in order to find those they have to parse their way to them.
You could stick the command in a temporary variable, and then execute the variable if your condition is true. I just ran the following on my system:
> if [ true ]; then echo hi; else [blah]=(--4); fi
-bash: syntax error near unexpected token `--4'
I get a syntax error as you describe. If I then do:
> if [ true ]; then echo hi; else var="[blah]=(--4)" && eval "${var}"; fi
hi
then it echos hi (no error). Finally if I do:
> if [ ]; then echo hi; else var="[blah]=(--4)" && eval "${var}"; fi
-bash: syntax error near unexpected token `--4'
Then it attempted to run the code, and generates an error based on trying to run the code.
I'm getting this error
Syntax error: redirection unexpected
in the line:
if grep -q "^127.0.0." <<< "$RESULT"
How I can run this in Ubuntu?
<<< is a bash-specific redirection operator (so it's not specific to Ubuntu). The documentation refers to it as a "Here String", a variant of the "Here Document".
3.6.7 Here Strings
A variant of here documents, the format is:
<<< word
The word is expanded and supplied to the command on its
standard input.
A simple example:
$ cat <<< hello
hello
If you're getting an error, it's likely that you're executing the command using a shell other than bash. If you have #!/bin/sh at the top of your script, try changing it to #!/bin/bash.
If you try to use it with /bin/sh, it probably assumes the << refers to a "here document", and then sees an unexpected < after that, resulting in the "Syntax error: redirection unexpected" message that you're seeing.
zsh and ksh also support the <<< syntax.
if grep -q "^127.0.0." <<< "$RESULT"
then
echo IF-THEN
fi
is a Bash-specific thing. If you are using a different bourne-compatable shell, try:
if echo "$RESULT" | grep -q "^127.0.0."
then
echo IF-THEN
fi
It works for me on Ubuntu, if I complete you IF block:
if grep -q "^127.0.0." <<< "$RESULT"; then echo ""; fi
How to check the correctness of the syntax contained in the ksh shell script without executing it? To make my point clear: in perl we can execute the command:
perl -c test_script.pl
to check the syntax. Is something similar to this available in ksh?
ksh -n
Most of the Borne Shell family accepts -n. tcsh as well.
I did a small test with the following code:
#!/bin/bash
if [ -f "buggyScript.sh" ; then
echo "found this buggy script"
fi
Note the missing ] in the if. Now I entered
bash -n buggyScript.sh
and the missing ] was not detected.
The second test script looked like this:
#!/bin/bash
if [ -f "buggyScript.sh" ]; then
echo "found this buggy script"
Note the missing fi at at end of the if. Testing this with
bash -n buggyScript.sh
returned
buggyScript.sh: line 5: syntax error: unexpected end of file
Conclusion:
Testing the script with the n option detects some errors, but by no means all of them. So I guess you really find all error only while executing the script.
The tests that you say failed to detect syntax errors, where not in fact syntax errors...
echo is a command (OK a builtin, but still a command) so ksh/bash are not going to check the spelling/syntax of your command.
Similarly "[" is effectively an alias for the test command, and the command expects the closing brace "]" as part of its syntax, not ksh/bash's.
So -n does what it says on the tin, you just haven't read the tin correctly! :-)