Ubuntu 16.04
Bash 4.3.48
Why does shellcheck
fail when a source file is representing the $variables at the top of a script?
Here is a simple script:
#!/bin/bash
. .sourcefile
echo "Today is ${day}."
Here is my source file:
day="Monday"
Here is the reply from shellcheck
:
me@myserver:~$ shellcheck start.sh
In start.sh line 5:
echo "Today is ${day}."
^-- SC2154: day is referenced but not assigned.
Is there a way to let shellcheck
know the $variables are in the source file?
@Dash-o explained the procedure below:
First, add the source directive on the line above the source file declaration like so:
# shellcheck source=/path/to/sourcefile
#!/bin/bash
# shellcheck source=./.sourcefile
. .sourcefile
echo "Today is ${day}."
Next, execute shellcheck
with the -x option before the script like so:
shellcheck -x start.sh
me@myserver:~$ shellcheck -x start.sh
When using the -x option, shellcheck
will follow the source file declared directly below the source directive. When I executed the command, I received the following error:
me@myserver:~$ shellcheck -x start.sh
unrecognized option `-x'
Usage: shellcheck [OPTIONS...] FILES...
-e CODE1,CODE2.. --exclude=CODE1,CODE2.. exclude types of warnings
-f FORMAT --format=FORMAT output format
-s SHELLNAME --shell=SHELLNAME Specify dialect (bash,sh,ksh)
-V --version Print version information
@Bayou mentioned my OS needed a newer version of shellcheck
. I checked my Ubuntu 16.04 installation. My server had shellcheck
0.3.7, which is the latest version Ubuntu 16.04 had to offer, so I grabbed the latest binary from the shellcheck
developers and installed it.
me@myserver:~$ mkdir .work && cd .work
me@myserver:~/.work$ wget -q https://github.com/koalaman/shellcheck/releases/download/stable/shellcheck-stable.linux.x86_64.tar.xz
me@myserver:~/.work$ ls
shellcheck-stable.linux.x86_64.tar.xz
me@myserver:~/.work$ tar xvf shellcheck-stable.linux.x86_64.tar.xz
shellcheck-stable/README.txt
shellcheck-stable/LICENSE.txt
shellcheck-stable/shellcheck
me@myserver:~/.work$ sudo chown root: shellcheck-stable/shellcheck
me@myserver:~/.work$ sudo mv /usr/bin/shellcheck .
me@myserver:~/.work$ sudo mv shellcheck-stable/shellcheck /usr/bin/
me@myserver:~/.work$ cd ../
me@myserver:~$ rm -rf .work/
me@myserver:~$ shellcheck -V
ShellCheck - shell script analysis tool
version: 0.7.1
license: GNU General Public License, version 3
website: https://www.shellcheck.net
I ran the command shellcheck -x start.sh
and I received zero errors.
me@myserver:~$ shellcheck -x start.sh
I then forced shellcheck
to give me a few errors. I added cat $myVariable
to the end of my script.
me@myserver:~$ echo "cat \$myVariable" >> start.sh
me@myserver:~$ cat start.sh
#!/bin/bash
# shellcheck source=./.sourcefile
. .sourcefile
echo "Today is ${day}."
cat $myVariable
I tested my theory and shellcheck
followed my sourcefile and gave me errors I was expecting.
me@myserver:~$ shellcheck -x start.sh
In start.sh line 7:
cat $myVariable
^---------^ SC2154: myVariable is referenced but not assigned.
^---------^ SC2086: Double quote to prevent globbing and word splitting.
Did you mean:
cat "$myVariable"
For more information:
https://www.shellcheck.net/wiki/SC2154 -- myVariable is referenced but not ...
https://www.shellcheck.net/wiki/SC2086 -- Double quote to prevent globbing ...
Then I executed shellcheck
without the -x option and to my surpise I received the following errors:
me@myserver:~$ shellcheck start.sh
In start.sh line 4:
. .sourcefile
^---------^ SC1091: Not following: ./.sourcefile was not specified as input (see shellcheck -x).
In start.sh line 6:
echo "Today is ${day}."
^----^ SC2154: day is referenced but not assigned.
In start.sh line 7:
cat $myVariable
^---------^ SC2154: myVariable is referenced but not assigned.
^---------^ SC2086: Double quote to prevent globbing and word splitting.
Did you mean:
cat "$myVariable"
For more information:
https://www.shellcheck.net/wiki/SC2154 -- day is referenced but not assigned.
https://www.shellcheck.net/wiki/SC1091 -- Not following: ./.sourcefile was ...
https://www.shellcheck.net/wiki/SC2086 -- Double quote to prevent globbing ...
So shellcheck
updated to the latest version and without the -x option, will also give you an error about you mising the -x option on the command line. So I decided to comment out the sourcefile directive in my start.sh
me@myserver:~$ sed -i '3s/./#\ &/' start.sh
me@myserver:~$ cat start.sh
#!/bin/bash
# # shellcheck source=./.sourcefile
. .sourcefile
echo "Today is ${day}."
cat $myVariable
Now to see what shellcheck
thinks
me@myserver:~$ shellcheck -x start.sh
In start.sh line 7:
cat $myVariable
^---------^ SC2154: myVariable is referenced but not assigned.
^---------^ SC2086: Double quote to prevent globbing and word splitting.
Did you mean:
cat "$myVariable"
For more information:
https://www.shellcheck.net/wiki/SC2154 -- myVariable is referenced but not ...
https://www.shellcheck.net/wiki/SC2086 -- Double quote to prevent globbing ...
Whaaaaa? So it seems the sourcefile directive is really not needed with my simple script or is shellcheck still seeing the sourcefile directive being commented out with the number sign as the number sign already starts the sourcefile directive? So I removed the sourcefile directive altogether and commented out the last line which references the myVariable variable that is not assigned in the sourcefile.
me@myserver:~$ sed -i '3d' start.sh
me@myserver:~$ sed -i '$d' start.sh
me@myserver:~$ cat start.sh
#!/bin/bash
. .sourcefile
echo "Today is ${day}."
Now to see what shellcheck
reports:
me@myserver:~$ shellcheck -x start.sh
No errors with the -x option. Now to check if the sourcefile directive is not needed at the top of a simple shell script with latest version of shellcheck
on Ubuntu 16.04, I executed shellcheck
without the -x option.
me@myserver:~$ shellcheck start.sh
In start.sh line 3:
. .sourcefile
^---------^ SC1091: Not following: .sourcefile was not specified as input (see shellcheck -x).
In start.sh line 5:
echo "Today is ${day}."
^----^ SC2154: day is referenced but not assigned.
For more information:
https://www.shellcheck.net/wiki/SC2154 -- day is referenced but not assigned.
https://www.shellcheck.net/wiki/SC1091 -- Not following: .sourcefile was no...
So, in short, if shellcheck
is not following your source file, update shellcheck
from the developer's github - (https://github.com/koalaman/shellcheck) and inform shellcheck
there is a sourcefile to follow by using the -x option like so:
shellcheck -x script.sh
I hope this helps someone as this site helps me each and everyday!
Shellcheck is a static analysis tool. It does not handle dynamic paths (based on variables, or expressions). As an alternative, consider adding the source directive.
Example:
# shellcheck source=./lib.sh
source "$(find_install_dir)/lib.sh"
The source= directive tells shellcheck the location of the dynamically generated filename. From the question, this should be the (most likely, relative) location of the .sourcefile
.
Documented in https://github.com/koalaman/shellcheck/blob/master/shellcheck.1.md