【问题标题】:Bash semicolon being equal to newline is not exactly true?Bash 分号等于换行符不完全正确?
【发布时间】:2018-06-26 02:30:24
【问题描述】:

我在多篇文章中读到分号 (;) 在类 UNIX 外壳中等于换行。
但是,以下内容让我感到困惑,我也没有运气用谷歌搜索它。

我猜这是 shell 中 do 的问题,但“bash 分号 do”并不是最适合 google 的搜索词组合。

下面是一个简单的for 声明。

for i in {1..10}
do
echo "hi"
echo "bye"
done

正如许多 Stack Overflow 专家所发布的那样,每个换行符都可以用分号代替。

所以.. 我们有以下“相同”声明。

for i in {1..10}; do; echo "hi"; echo "bye"; done

我们得到:

-bash: syntax error near unexpected token `;'

分号到底是什么?这只是do 的一个独特问题吗?

【问题讨论】:

  • AFAIK,dothen 几乎是一个独特的问题(来自 if..then)。我想不出另一种情况,用; 替换换行符会失败(并且 heredocs 是他们自己的特殊事物,其中空格很重要,所以这不算数)。不过,我已经准备好被纠正了! =)

标签: bash shell


【解决方案1】:

看着syntax of the for/do loop

for <i>name</i> [ [in [<i>words</i> …] ] ; ] do <i>commands</i>; done

我们可以看到do 后面紧跟着commands,所以在do 之后使用换行符不会替换分号,而是空格。

compound commands 的描述也说

在大多数情况下,复合命令描述中的命令列表可以通过一个或多个换行符与命令的其余部分分隔,并且后面可以用换行符代替分号。

但它没有说您可以插入随机分号。 “每个换行符都可以用分号代替”这句话太笼统了,不正确。

更多手动证据:在关于lists of commands 的部分中,它说(强调我的):

list 是一个或多个管道的序列,由 ;&amp;&amp;&amp;|| 中的一个运算符分隔,并且可选地由 ;、@987654336 之一终止@,或newline

在这些列表运算符中,&amp;&amp;|| 具有相同的优先级,其次是 ;&amp;,它们具有相同的优先级。

list 中可能出现一个或多个换行符的序列来分隔命令,相当于分号。

所以换行符相当于命令列表中的分号

【讨论】:

  • 谢谢。我没有想到换行符可以在某些情况下替换分号和空格。虽然它仍然很混乱。这不像你可以做my_script.sh&lt;press enter&gt;params。我猜换行符 \n 有时可以替换为空格或分号,但有时不能?
  • @GyuhyeonLee 我会说换行符和空格可以互换的“经验”准则是“当您按下回车键后显示辅助提示符(通常为&gt;)时”,即shell 期望你的命令继续。
【解决方案2】:

这不是 只是 do;在许多情况下,shell 允许在不允许分号的情况下使用换行符。

这是其中的大部分(省略了引号内的换行符或分号的使用,它们总是彼此不同):

  1. &amp;&amp;|| 之后

    some_command &&
    some_other_command
    
  2. 在管道之后(|):

    some_producer |
    some_consumer
    
  3. for 语句中的in 之前:

    for x
    in $(produce_values); do
    

    虽然空命令是非法的,但 shell 语法确实允许在 for 命令中使用空值列表,因此 for x in; do do_something; done 是合法的,因此使用换行符而不是分号编写的内容相同。

  4. case 语句中的in 之前或之后;也在每个模式的关闭) 和关闭每个案例的;; 之后:

    case $x
    in
    pattern)
      do_something ;;
    esac
    
  5. 在关键字ifthenelifelsewhileuntil 之后:

    if
      some_condition
    then
      do_something
    else
      do_something_else
    fi
    
  6. {( 之后打开复合命令或子shell:

    {
       a_command
       another_command
    }
    
    (
       a_command
       another_command
    )
    

    类似地,在启动命令替换的$( 之后:

    a=$(
      echo hello
    )
    

    在 bash 中,这也适用于进程替换中的 (&lt;(...)。请参阅下文,了解在处理条件和算术替换的 bash 扩展中略有不同的处理方式。

  7. 函数定义中)之后:

    my_function()
    {
      do_something
    }
    
  8. 在终止命令的;&amp; 之后:

    do_something;
    do_something_in_background &
    

    (注意空命令是非法的,所以do_something; ;会被拒绝。)

我从shell grammar in the Posix standard 中获取了该列表。 Bash 允许在其他地方换行;当我写这个答案时,我想不出任何东西,但@BenjaminW 提醒了我:

  • 在带括号的数组字面量中,无论是在数组赋值还是数组声明中,换行符都被视为空格:

    a+=(
      first_thing
      second_thing
    )
    
    local -A b=(
      [x]="value of x"
      [y]="value of y"
    )
    

然后我想起了这些其他伪引用环境:

  • Bash 还接受换行符作为算术表达式中的空格:

    i=$((
       i + 
         3 * j
    ))
    
    if ((
      i + 3 * j
      >
      9
    ))
    

    [[ 之后或]] 之前[[ 风格的条件语句:

    if
    [[
          $a -eq "done"
    ]]    
    then break
    fi
    

【讨论】:

  • 另外对于 Bash:在数组的声明中,arr=(\nel1\nel2\n) 可以,arr=(;el1;el2;) 不行。
  • @benjaminW:是的,数组声明中的括号是一种引用。我忘了那个;谢谢。
  • 特别是对于关联数组(如您的示例),使用换行符可以将可读性提高一个数量级,IMO。
  • 感谢您的友好解释。手册页真的是折磨,我不知道如何搜索这些东西。我想我最好习惯手册页。
  • @GyuhyeonLee 如果您阅读了像极力推荐的BashGuide 这样的最佳实践指南,您可以按照示例中的语法和风格避免大多数问题;你的问题已经深入细节。这当然不是一件坏事,但在开始时可能会令人沮丧。
【解决方案3】:

他们在 zsh 中工作:

for i in {1..10}; do; echo "hi"; echo "bye"; done

; for i in {1..10}; do; echo "hi"; echo "bye"; done

; for i in {1..10}; do; echo "hi"; echo "bye"; done;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-01-17
    • 1970-01-01
    • 2020-05-07
    • 1970-01-01
    • 2013-08-26
    • 1970-01-01
    • 1970-01-01
    • 2021-11-17
    相关资源
    最近更新 更多