There should a new directive to instruct shellcheck to stop processing one it reaches that line.
I sometimes have the need to inline certain foreign scripts (awk, perl, sed, etc.) in the end of the script so it can made self-contained, deployed easily and easily maintainable (regular heredocs can quickly become cumbersome to manage as they sit next to the code).
At some version in the past, setting the following instruction (without a directive) would work, ignoring any lines after it:
# shellcheck disable
#!/bin/bash
read_inline_doc(){
local __sed__;
__sed__=$(command -v sed);
# shellcheck disable=SC2016
"${__sed__}" \
'1,/[B]EGIN DEFINITION/d;/[E]ND DEFINITION/,$d;' \
"${BASH_SOURCE[0]}";
}
read_inline_doc;
exit 0; # do not allow script to run into here docs
#---------------------------- end of script ----------------------------
#--------------------------- HEREDOC CONTENT ---------------------------
#
#BEGIN DEFINITION
my %perl_hash= (
one => '1',
two => '2',
);
#END DEFINITION
#
#------------------------- END OF HEREDOC CONTENT ----------------------
It will try to interpret the heredoc, which most certainly will fail;
nothing - ignores the inlined heredoc
or prints a warning to note the analysis was stopped at that line.
There is an workaround but it will not generate any warnings about the skipped processing: surrounding the entire HEREDOC CONTENT in quotes makes shellcheck ignore the whole block, as in this example:
#!/bin/bash
read_inline_doc(){
local __sed__;
__sed__=$(command -v sed);
# shellcheck disable=SC2016
"${__sed__}" \
'1,/[B]EGIN DEFINITION/d;/[E]ND DEFINITION/,$d;' \
"${BASH_SOURCE[0]}";
}
read_inline_doc;
exit 0; # do not allow script to run into here docs
#---------------------------- end of script ----------------------------
"
#--------------------------- HEREDOC CONTENT ---------------------------
#
#BEGIN DEFINITION
my %perl_hash= (
one => '1',
two => '2',
);
#END DEFINITION
#
#------------------------- END OF HEREDOC CONTENT ----------------------
"
This is not a priority feature.
I guess that would be easy to implement but having more than one language in a file is a bug so really you should have a tool that mixes your files together for deployment and shellcheck/Perl::Lint before they're mixed.
I disagree. having multiple languages in a file should not be considered a bug but a common pattern; anyways a global disable flag is desirable regardless of whether this is a bug or not.
My USD 0.02: I just did a quick test. Running this:
#!/bin/bash
echo hi
ishk-)*(
exit 0;
ishk-)*(
gives:
./x: line 5: syntax error near unexpected token `)'
./x: line 5: `ishk-)*('
However, running this:
#!/bin/bash
echo hi
exit 0;
ishk-)*(
gives:
So, in theory, anything after an exit should be ignored by shellcheck because bash ignores it. HOWEVER, it gets tricky. What if you end your script like:
if foo
then
exit 1
else
exit 0
fi
Bash will never see anything past this block. But can shellcheck do that kind of static analysis? And if it can, then what it should REALLY do is put out an error "SC6789: Unreachable code after exit." And then you'd simply add a disable for 6789 before your other-language code. BUT those disables are really line-based not block based. Unless you then put your other code in a bash block.
And at that point, you might as well put it in a heredoc.
ShellCheck currently can't do that: it doesn't build a proper control flow graph, which hampers a lot of analysis including dead code detection. I've been wanting to do that for years, but haven't found the time.
Bash is a tricky language to do this for, but ShellCheck is fortunate in that it's not an optimizing compiler that needs to always be correct. For example, in all these cases, the unreachable code can technically be reached if the script was invoked with an exported function exit() { true; }
Then heredoc it is.
EDITED: I have a work around that makes the request moot for my purposes.
Use braces to bundle affected statements:
e.g.
# shellcheck disable=2155,2034
{
declare -r _u="$(setterm -underline on)" # Start underline
declare -r u_="$(setterm -underline off)" # End underline
declare -r _b="$(setterm -bold on)" # Start bold
declare -r b_="$(setterm -bold off)" # End bold
declare -r _r="$(setterm -reverse on)" # Start reverse
declare -r r_="$(setterm -reverse off)" # End reverse
}
This takes care of a scope, but not for "the rest of the script" (which was the initial issue flagged here).
OLD ENTRY (can now be ignored)
How about just providing a scope for the current ignore directive?
# shellcheck disable=<sc_list> on
<code>
# shellcheck disable=<sc_list> off
A bit cumbersome because you have to maintain your "list" in both statements, but I find myself in a situation where I need to ignore a specific error for a specific block of code all the time...;
Note that the lists are independent, you could do something like:
#shellcheck disable=1 on
<code>
# shellcheck disable=2,3 on
<code>
# shellcheck disable=1,2 off
<code>
# shellcheck disable=3 off
Of course, if the sources/calls another script.. do we put it under our control if the ignore propagates? I wouldn't think so: the disable directive applies to the current script only, and we should keep it that way...
This seems to be the least intrusive syntax?