【问题标题】:Will bash script pre-parse the syntax?bash 脚本会预先解析语法吗?
【发布时间】:2018-01-22 20:36:37
【问题描述】:

我正在运行 bash 脚本,该脚本需要为 SunOs 和 Linux 运行不同的代码,并且我从不应该为真的部分代码中得到语法错误。我没想到会这样,因为我认为 Bash 是作为解释器工作的。

SunOS 上的 bash 版本是 2.5,Linux 上是 4.1。它抱怨的语法仅支持 3.1 版本。

我尝试使用“else”子句禁用较新的代码,但它看起来仍然是预解析的。

我的脚本还有“:”而不是“#!/bin/sh”作为第一行。

test.sh:

:
echo "`uname`"
if [ `uname` = "SunOS" ]
 then
    echo "do old stuff"
 else
    echo "new stuff"
    arr=($(grep "^X1" ../foo.txt | sed 's/.*=//'))
fi

错误是

> ./test.sh
SunOS
./test.sh: syntax error at line 8: `arr=' unexpected

如果我注释错误行,那么它会正常工作:

:
echo "`uname`"
if [ `uname` = "SunOS" ]
 then
    echo "do old stuff"
 else
    echo "new stuff"
    #arr=($(grep "^X1" ../foo.txt | sed 's/.*=//'))
fi

结果是

> ./test.sh
SunOS
do old stuff

我的问题是如何在不发表评论的情况下修复此语法错误?我必须有“if/else”才能在不同的机器上运行这个脚本。

【问题讨论】:

  • 从 3.1 开始只支持什么?您在此处使用的数组语法至少在 2.05 中很好。您确定您使用的是bash 而不是sh
  • 如果将: 替换为正确的主题标签会发生什么?祝你好运。
  • 我如何知道具体使用了什么(bash 或 sh)?这是作为构建过程的一部分执行的。
  • @shelter 我将其替换为 "#! /bin/sh 并发生同样的错误
  • @angie 使用 #!/bin/bash.

标签: bash solaris


【解决方案1】:

至少从版本 2 开始,bash 就支持该数组语法;如果您在那里遇到错误,那是因为您的脚本根本没有在 bash 下运行,而是在其他一些 shell 下运行。这可能与您的以: 而不是shebang 行开头的脚本有很大关系,这意味着取决于运行脚本的任何内容来确定使用什么来运行它,但结果不一致。我强烈建议使用适当的 shebang 线。如果 bash 在可预测的位置不存在,您可以使用#!/usr/bin/env bash。如果 bash 可能不在 PATH 中,您可以使用类似脚本序言 here -- a #!/bin/sh shebang 后跟命令来查找并切换到 bash。

关于预解析的问题:是的,bash 和其他shell 在执行if 构造之前会一直解析到fi 关键字。他们需要找到thenelsefi 关键字,以便弄清楚他们将要执行什么以及他们将要跳过什么,并且为了找到那些他们必须解析他们的通往他们的道路。

【讨论】:

    【解决方案2】:

    您可以将命令粘贴到临时变量中,然后在您的条件为真时执行该变量。我刚刚在我的系统上运行了以下命令:

    > if [ true ]; then echo hi; else [blah]=(--4); fi
    -bash: syntax error near unexpected token `--4'
    

    如您所述,我收到语法错误。如果我这样做:

    > if [ true ]; then echo hi; else var="[blah]=(--4)" && eval "${var}"; fi
    hi
    

    然后它回显 hi(没有错误)。最后,如果我这样做:

    > if [ ]; then echo hi; else var="[blah]=(--4)" && eval "${var}"; fi
    -bash: syntax error near unexpected token `--4'
    

    然后它尝试运行代码,并根据尝试运行代码生成错误。

    【讨论】:

    • 这很接近,但是你需要使用eval来解析字符串中的shell语法。
    • 哎呀,是的……我的错
    • 你应该双引号引用变量,尤其是在做危险的事情时,比如eval -- eval "${var}" 而不是eval ${var}。如果没有双引号,在某些情况下您可能会得到非常奇怪的结果。
    • 我尝试了这个建议,但似乎没有帮助。它不会打印语法错误,但不会正确填充 arr
    • 对不起,你是说在“新东西”的情况下它没有填充数组吗?尝试将 eval 替换为 echo,然后将输出剪切并粘贴到命令提示符上,看看它是否正常工作。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-05-20
    • 2021-12-03
    • 1970-01-01
    • 2019-02-17
    • 2020-02-09
    • 2022-01-25
    • 1970-01-01
    相关资源
    最近更新 更多