找到 bash 脚本中丢失的引号的最简单方法?

找到 bash 脚本中丢失的引号的最简单方法?

我有一个 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 非常好,每个好的脚本都应该经过它。

相关内容