gpt4 book ai didi

shell - `for NAME do ...` 中的 NAME 后是否禁止使用分号?

转载 作者:行者123 更新时间:2023-12-04 15:19:58 25 4
gpt4 key购买 nike

bash 手册列出了 for 的语法。复合语句为for name [ [ in [ word ... ] ] ; ] do list ; done这意味着 do 之前的分号如果 in 是可选的子句省略。 [笔记2]。
但是,Posix 规范仅列出了 for_clause 的以下三个产生式:

for_clause       : For name linebreak                            do_group
| For name linebreak in sequential_sep do_group
| For name linebreak in wordlist sequential_sep do_group
;
供引用, linebreak是一个可能为空的序列 NEWLINEsequential_sep是分号或 NEWLINE , 可能后跟 NEWLINE 的序列:
newline_list     :              NEWLINE
| newline_list NEWLINE
;
linebreak : newline_list
| /* empty */
;
separator : separator_op linebreak
| newline_list
;
sequential_sep : ';' linebreak
| newline_list
;
据我所知,这禁止语法 for foo; do :; done .
实际上,我尝试过的所有 shell(bash、dash、ksh 和 zsh)都接受 for foo; do :; donefor foo do :; done毫无怨言,无论 Posix 还是他们自己的文档 [注 3]。
这是 Posix 标准语法中的意外遗漏,还是应该将分号在该语法中的使用视为标准的(普遍实现的)扩展?
附录
for loop 的 XCU 描述中, Posix 似乎坚持换行:

The format for the for loop is as follows:

for name [ in [word ... ]]

do

compound-list

done


但是,在基本原理卷中,明确指出语法旨在成为最后一个词:

The format is shown with generous usage of <newline> characters. See the grammar in XCU Shell Grammar for a precise description of where <newline> and <semicolon> characters can be interchanged.



笔记
  • 显然,这是第一个配对 的 SO 问题和 .没有 ,这可能更合适。
  • bash手册对换行符并不完全明确;它说的是:

    In most cases a list in a command's description may be separated from the rest of the command by one or more newlines, and may be followed by a newline in place of a semicolon.


    这清楚地表明 done 前面的分号可以用换行符代替,但似乎没有提到可以对do前面的分号进行同样的转换.
  • 两者 kshzsh似乎坚持在 name 之后有一个分号或换行符,虽然实现并不坚持它。ksh手册页列出的语法如下:

    for vname [ in word ... ] ;do list ;done


    (我相信 ;do;done 中的分号代表“分号或换行符”。我找不到任何明确的声明,但这是理解语法描述的唯一方法。)zsh手册显示:

    for name ... [ in word ... ] term do list done
        where term is at least one newline or ;.


  • 最佳答案

    好找!我没有明确的答案,但以下是源代码对此的说明:

    它确实在 the original Bourne shell 中无效来自 AT&T UNIX v7:

    (shell has just read `for name`):
    IF skipnl()==INSYM
    THEN chkword();
    t->forlst=item(0);
    IF wdval!=NL ANDF wdval!=';'
    THEN synbad();
    FI
    chkpr(wdval); skipnl();
    FI
    chksym(DOSYM|BRSYM);

    鉴于这个片段,它似乎不是一个有意识的设计决定。这只是作为 in 的一部分处理的分号的副作用。组,当没有“in”时完全跳过。

    Dash 同意它是 not valid in Bourne ,但将其添加为扩展名:
            /*
    * Newline or semicolon here is optional (but note
    * that the original Bourne shell only allowed NL).
    */

    Ksh93 claims that it's valid ,但没有说明上下文:
    /* 'for i;do cmd' is valid syntax */
    else if(tok==';')
    while((tok=sh_lex(lexp))==NL);

    Bash 没有评论,但 explicitly adds support for this case :
    for_command:    FOR WORD newline_list DO compound_list DONE
    {
    $$ = make_for_command ($2, add_string_to_list ("\"$@\"", (WORD_LIST *)NULL), $5, word_lineno[word_top]);
    if (word_top > 0) word_top--;
    }
    ...
    | FOR WORD ';' newline_list DO compound_list DONE
    {
    $$ = make_for_command ($2, add_string_to_list ("\"$@\"", (WORD_LIST *)NULL), $6, word_lineno[word_top]);
    if (word_top > 0) word_top--;
    }

    在 zsh 中,它只是一个 side effect of the parser :
    while (tok == SEPER)
    zshlex();

    其中( SEPER ; or linefeed )。因此,zsh 愉快地接受了这个循环:
    for foo; ; 
    ;
    ; ; ; ; ;
    ; do echo cow; done

    对我来说,这一切都指向 POSIX 中的有意省略,并作为扩展得到了广泛和有意的支持。

    关于shell - `for NAME do ...` 中的 NAME 后是否禁止使用分号?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36896830/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com