当源文件表示脚本顶部的变量时,为啥 shellcheck 会失败?

Posted

技术标签:

【中文标题】当源文件表示脚本顶部的变量时,为啥 shellcheck 会失败?【英文标题】:Why does shellcheck fail when a source file is representing the variables at the top of a script?当源文件表示脚本顶部的变量时,为什么 shellcheck 会失败? 【发布时间】:2020-02-23 12:46:03 【问题描述】:

Ubuntu 16.04 重击 4.3.48

为什么当源文件代表脚本顶部的 $variables 时,shellcheck 会失败?

这是一个简单的脚本:

#!/bin/bash

. .sourcefile

echo "Today is $day."

这是我的源文件:

day="Monday"

这是shellcheck的回复:

me@myserver:~$ shellcheck start.sh

In start.sh line 5:
echo "Today is $day."
               ^-- SC2154: day is referenced but not assigned.

有没有办法让shellcheck 知道$variables 在源文件中?


这是我在 Ubuntu 16.04 上所做的工作

@Dash-o 解释了以下过程:

首先,在 source file 声明上方的行中添加 source 指令,如下所示:# shellcheck source=/path/to/sourcefile

#!/bin/bash

# shellcheck source=./.sourcefile
. .sourcefile

echo "Today is $day."

接下来,在脚本之前使用 -x 选项执行shellcheck,如下所示:shellcheck -x start.sh

me@myserver:~$ shellcheck -x start.sh

当使用 -x 选项时,shellcheck 将跟随直接在 source 指令 下声明的 源文件。当我执行命令时,我收到以下错误:

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 提到我的操作系统需要更新版本的shellcheck。我检查了我的 Ubuntu 16.04 安装。我的服务器有 shellcheck 0.3.7,这是 Ubuntu 16.04 必须提供的最新版本,所以我从 shellcheck 开发人员那里获取了最新的二进制文件并安装了它。

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

我运行了命令shellcheck -x start.sh,我收到了零错误。

me@myserver:~$ shellcheck -x start.sh

然后我强迫shellcheck 给我一些错误。我在脚本末尾添加了cat $myVariable

me@myserver:~$ echo "cat \$myVariable" >> start.sh  
me@myserver:~$ cat start.sh
#!/bin/bash

# shellcheck source=./.sourcefile
. .sourcefile

echo "Today is $day."
cat $myVariable

我测试了我的理论,shellcheck 跟踪了我的源文件,给了我预期的错误。

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 ...

然后我在没有 -x 选项的情况下执行了shellcheck,令我惊讶的是,我收到了以下错误:

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 ...

所以 shellcheck 更新到最新版本并且没有 -x 选项,也会给你一个错误,告诉你你在命令行上错过了 -x 选项.所以我决定在我的 start.sh 中注释掉 sourcefile 指令

me@myserver:~$ sed -i '3s/./#\ &/' start.sh
me@myserver:~$ cat start.sh
#!/bin/bash

# # shellcheck source=./.sourcefile
. .sourcefile

echo "Today is $day."
cat $myVariable

现在看看shellcheck 是怎么想的

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 ...

哇啊啊?因此,我的简单脚本似乎确实不需要 sourcefile 指令,或者 shellcheck 仍然看到 sourcefile 指令 被数字符号注释掉,因为数字符号已经开始源文件指令?因此,我完全删除了 sourcefile 指令,并注释掉了最后一行引用了未在源文件中分配的 myVariable 变量。

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."  

现在看看shellcheck 报告了什么:

me@myserver:~$ shellcheck -x start.sh

-x 选项没有错误。现在检查 sourcefile 指令 在 Ubuntu 16.04 上使用最新版本 shellcheck 的简单 shell 脚本的顶部是否不需要,我在没有 -x 的情况下执行了 shellcheck strong> 选项。

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...

所以,简而言之,如果 shellcheck 没有关注您的源文件,请从开发者的 github - (https://github.com/koalaman/shellcheck) 更新 shellcheck 并通知 shellcheck 有一个源文件可以使用 -x 选项如下:

shellcheck -x script.sh  

我希望这对某人有所帮助,因为这个网站每天都对我有所帮助!

【问题讨论】:

"$(pwd)/" 部分不是必需的。你可以使用. .sourcefile @CuriousSam :我不认为 shell 检查实际上是在读取源文件。在一般情况下,Shellcheck 无法知道您正在采购什么文件(想象一下您会采购类似 . /$(myprog $RANDOM) 的文件。特别是在您的情况下,shellcheck 无法合理地得出 pwd 的值。 我更正了$(pwd) 大部分应该是Answer 【参考方案1】:

Shellcheck 是一种静态分析工具。它不处理动态路径(基于变量或表达式)。作为替代方案,请考虑添加源指令。

例子:

# shellcheck source=./lib.sh
source "$(find_install_dir)/lib.sh"

source= 指令告诉 shellcheck 动态生成的文件名的位置。从问题来看,这应该是.sourcefile 的(最有可能的,相对的)位置。

记录在https://github.com/koalaman/shellcheck/blob/master/shellcheck.1.md

【讨论】:

我阅读了文档并尝试了shellcheck source-path=./.sourcefile start.sh 并打印了shellcheck: source-path=./.sourcefile: openFile: does not exist (No such file or directory)。我也累了shellcheck source=./.sourcefile start.sh,但还是失败了。我一定有错误的语法? 您必须在脚本中插入注释,就在“源”语句之前。这不是命令行参数。请查看文档链接 正确。现在一切正常。感谢您的帮助。 我再次从 devs github 更新了 shellcheck,似乎不再需要 sourcefile 指令,但 -x 选项仍然存在需要通知shellcheck 查找在行首使用单词source 或句点. 声明的源文件。 还值得注意的是,可以使用-e SC1090 opton 禁用此检查。【参考方案2】:

我使用 shellcheck 0.4.4,它还说:

在 start.sh 第 2 行: . "$(pwd)"/.sourcefile ^-- SC1090: 不能跟随非常量源。使用指令指定位置。

这意味着您必须使用绝对路径,但newer 版本可能支持-P

如果你切换到一个非常量源,它就不能正常工作,因为.sourcefile 需要一个shebang,你必须像这样用-x 添加这个文件:

shellcheck -x .sourcefile start.sh

它仍然会抱怨:

day="星期一" ^-- SC2034: day 似乎未使用。验证或导出。

【讨论】:

这是故意触发 shellcheck 警告的。 day="Monday" 在源文件中。在使用 shellcheck 并在脚本中调用源文件时,您必须在脚本顶部添加 # shellcheck source=./.sourcefile.sh。然后你告诉 shellcheck 在命令行 shellcheck -x start.sh 上用 -x 查找源代码 仍然 即使使用 source "$HOME"/.bashrc 也能做到这一点 @Fuseteam 试试# shellcheck source=~/.bashrc 同样的问题,最后我只是用# shellcheck source=/dev/null禁用了它

以上是关于当源文件表示脚本顶部的变量时,为啥 shellcheck 会失败?的主要内容,如果未能解决你的问题,请参考以下文章

为啥当我相对于父视图的底部进行约束时,它是从父视图的顶部操作的?现在是对的吗?

处理用户输入(第十四章)

为啥当我在 uiscrollview 顶部添加对象时,即使我将所有四个约束都设置为 0,对象也会下降一点?

为啥当我滚动到顶部然后在我的 API 应用程序上返回但在网页上正常运行时,我的页面顶部按钮口吃/滞后/粘住?

为啥我的脚本(旨在在游戏开始时消除重力)不起作用?

Shell脚本中的变量