我有一个 bash 脚本,目前有 700 多行长。经过一轮特别长的编辑后,现在出现如下错误:
./run_me.sh: line 693: unexpected EOF while looking for matching `''
./run_me.sh: line 702: syntax error: unexpected end of file
然而,我可以看到第 693 行没有任何问题。上面甚至没有引用。
我尝试过运行bash -x run_me.sh
,并且可以看到最后一行运行,但是该行也没有任何问题(并且该行和 693 之间的代码实际上是大部分代码)。
我可以注释掉整段代码,但随后我更有可能看到由于缺少函数等而导致的错误,而不是我收到的 EOF 错误。
那么,如果行号报告不正确,人们应该如何找到丢失的报价呢?
(为什么 bash 的行号报告如此之远?)
编辑
顺便说一句,我发现了我的特定错误(通过注释条带),这实际上是}
在任意行号处的变量扩展中丢失的,该行号与错误消息指示的行相距甚远 - 基于引号的语法突出显示在这里没有帮助,例如"${MY_ARRAY[@]"
(should be )中缺少的大括号"${MY_ARRAY[@]}"
。
答案1
一种低技术含量的方法是
tr -cd "'\n" < run_me.sh | awk 'length%2==1 {print NR, $0}'
删除tr
除单引号和换行符之外的所有字符,并awk
标识具有奇数个字符的行(即不匹配的引号)。单独检查它们;请注意,有效的字符串"That's not a bug!"
将被标记。
如果这没有突出问题,请使用tr -cd '"\n'
(查找不匹配的双引号)重试。 接下来,展开tr
允许()
、[]
、 最终{}
通过。此时,对输出进行手动检查就变得不太有效了;虽然(
and通常在同一行中匹配,而引号和方括号几乎总是如此,但and )
则不然。 (但是,寻找不匹配的情况会 发现OP实际存在的问题,即键入而不是 )。{
}
{
}
"${MY_ARRAY[@]"
"${MY_ARRAY[@]}"
如果您已将问题范围缩小到大括号不匹配,特别是如果您已缩小文件中的范围,请转至计划 B。在vim
(或vi
) 中打开文件。转至{
您认为出现错误之前的字符并键入%
。如果光标跳到}
您认为与{
您开始的位置匹配的位置,请前进到下一个{
并重复。如果它跳转到与您开始的}
位置不匹配的位置{
,则错误会发生在这两个大括号之间。如果它没有移动,则说明当前位置和文件末尾之间发生了错误。放大。
这种方法可能稍微更适合 C、C++ 和 Java 等语言的程序文件(如果它们的编译器做得不够好),但它对于 shell 脚本应该相当有效。
答案2
外部 linting 工具,例如外壳检查可以检测问题并且可能具有比bash
其自身更好的消息和位置。
对于主要是中间echo
带有 a 的语句的程序,ShellCheck 会告诉您它无法解析带引号的字符串。"${MY_ARRAY[1]"
它甚至将问题归咎于角色$
,并暗示参数扩展有问题。
ShellCheck 可与 Vim、Emacs、SublimeText 和 Atom(以及其他)配合使用。
答案3
最简单的方法?使用具有语法着色功能的编辑器,该编辑器可以识别您正在使用的 shell,并进行目视检查。当你看到一大片字符串颜色时,你就知道你漏掉了一个引号。几乎任何像样的编程编辑器都有语法着色。
语法着色有时会出错,但这通常表明您的程序太复杂,人类也可能会出错。
对于 shell 编程,请确保使用易于区分的字体 where "
、'
和。`
检查您是否无意中使用了看起来像 ASCII 引号的非 ASCII 字符,例如‘’“”
。
答案4
我使用 G-Man 的低技术解决方案解决了 2000 多行 bash 脚本中的一个大问题。
我只需添加以下行,该行对于奇数个双引号的作用与 G-Man 对单引号的答案相同。
tr -cd "\"\n" < my_script.sh | awk 'length%2==1 {print NR, $0}'
顺便说一句,shellcheck.net 非常好,每个好的脚本都应该经过它。