加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > 安全 > 正文

shell – 在NAME之后是否禁止使用分号?为NAME做…?

发布时间:2020-12-15 18:18:57 所属栏目:安全 来源:网络整理
导读:bash手册列出了for compound语句的语法 名称[[in [word …]]; ]列表; DONE 这意味着如果省略in子句,则do之前的分号是可选的. [笔记2]. 但是,Posix规范仅为for_clause列出以下三个产品: for_clause : For name linebreak do_group | For name linebreak in s
bash手册列出了for compound语句的语法

名称[[in [word …]]; ]列表; DONE

这意味着如果省略in子句,则do之前的分号是可选的. [笔记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是NEWLINE的可能空序列,而sequential_sep是分号或NEWLINE,可能后跟NEWLINE序列:

newline_list     :              NEWLINE
                 | newline_list NEWLINE
                 ;
linebreak        : newline_list
                 | /* empty */
                 ;
separator        : separator_op linebreak
                 | newline_list
                 ;
sequential_sep   : ';' linebreak
                 | newline_list
                 ;

据我所知,这禁止了foo的语法;做:;完成.

在实践中,我尝试的所有shell(bash,dash,ksh和zsh)都接受foo;做:;完成并为foo做:;没有投诉,无论Posix或他们自己的文件[注3].

这是Posix标准中语法中的意外遗漏,还是在该语法中使用分号是否应被视为标准的(通常实现的)扩展?

附录

在for循环的XCU描述中,Posix似乎坚持使用换行符:

The format for the for loop is as follows:

for name [ in [word ... ]]
do
compound-list
done

但是,在Rationale卷中,很明显语法是最后一个词:

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.

笔记

>显然这是第一个与shell和language-lawyer配对的SO问题.没有idle-curiosity,这可能更合适.
> 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.

这清楚地表明,前面的分号可以用换行符替换,但似乎没有提到可以对前面的分号执行相同的转换.
> ksh和zsh似乎都坚持在名称后面有分号或换行符,尽管实现并不坚持.

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,$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中的故意遗漏,并作为扩展广泛和有意地支持.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读