什么是(确切地说)“列表上下文”(和“字符串上下文”)?

ImH*_*ere 2 shell

我已经多次看到“列表上下文”和“字符串上下文”的使用。

我知道并理解在 perl 中使用此类描述。它们适用于 $ 和 @

但是,在 shell 描述中使用时:

它们似乎是一个没有在任何地方定义或
充其量只是记录不充分的术语。

根据谷歌的说法,POSIX 中没有对此的定义

这是(从这)它的要点吗?:

简而言之,在需要单词列表或模式的任何地方都需要双引号。在解析器需要原始字符串的上下文中,它们是可选的。

但这似乎是一个难以使用的术语。当“需要结果”时,我们如何才能找到“结果应该是什么”以了解它是字符串还是列表上下文。

或者它可以被精确和正确地定义吗?

Kaz*_*Kaz 12

在标准的 shell 语言中没有这样的概念。没有“上下文”,只有扩展步骤。

引号首先在生成单词的标记中识别。他们将单词粘合在一起,从而形成abc"spaces here"xyz一个“单词”。

需要理解的重要一点是,引号会在后续的扩展步骤中保留下来,并且原始引号与可能因扩展而出现的引号不同。

参数被扩展而不考虑双引号。但是,稍后会发生一个字段拆分过程,这可以追溯到第一次标记化。引号再次防止分裂,并再次被保留。

路径名扩展(“globbing”)发生在此拆分之后。保留的引号阻止了它:在引号内无法识别通配符。

最后,引号被称为“引用删除”的后期阶段删除。当然,只有原始报价!

POSIX在以易于理解的方式呈现过程方面做得很好;试图用无关的概念(可能会误导)揭开它的神秘面纱只会混淆理解。

人们抛出像“列表上下文”这样的临时概念的人应该将他们的想法形式化,以便它可以为所有处理提供完整的替代规范,这是等效的(产生相同的结果)。然后,避免在并行设计之间混合概念:使用一种解释或另一种解释。“列表上下文”或“字符串上下文”在 shell 扩展理论中是有意义的,在这些理论中,它们被很好地定义,并且处理步骤围绕这些概念进行组织。

如果我猜的话,那么“列表上下文”是指 shell 正在处理标记化单词列表,例如两个单词 list {foo} {abc" x "def}。引号不是第二个单词的一部分:它的内容实际上是abc x def; 它们是语义引号,可防止在空格上进行拆分。在这些引号中,我们有“字符串上下文”。

然而,这些扩展步骤的一种可能实现并不是实际将引号标识为原始引号,而是某种列表数据结构{foo} {abc" x "def},也就是说,其中引用部分被标识为不同的列表的列表各种节点(引号消失了)。使用 Lisp 符号可以是:

(("foo") ;; one-element word
 ("abc" (:dq-str " x ") "def")) ;; three-element word
Run Code Online (Sandbox Code Playgroud)

没有标签的节点是文字文本,:dq-str是双引号区域。另一种类型可以:sq-str用于单引号项。

扩展可以遍历这个结构,然后根据它是查看字符串对象、:dq-str表达式还是其他任何东西来做不同的事情。文件扩展和字段拆分将在两者:dq-str:sq-str. 但是参数扩展确实发生在:dq-str. 然后,“引用删除”将对应于最终传递,该传递获取片段并连接字符串,使内部列表结构变平并丢失类型指示符号,从而导致:

("foo"
 "abc x def") ;; plain string list, usable as command arguments
Run Code Online (Sandbox Code Playgroud)

现在,请注意我们在第二项中的("abc" (:dq-str " x ") "def"). 第一个和最后一个项目被展开:它们是列表的直接元素,所以我们可以说它们在“列表上下文”中。而中间" x "被包裹在一个:dq-str表达式中,所以它是“(双引号)字符串上下文”。

“列表”在“列表上下文”中所指的是任何人的猜测,没有像这样的明确定义的模型。是主词表吗?或者代表一个单词的块列表?


Sté*_*las 6

由于您引用的大多数事件都是我自己写的,我觉得我必须在这里给出答案,尽管我主要是转述@Gilles。

至少自 2004以来,我一直在使用列表上下文标量/非列表上下文(比字符串上下文更好,如果不被理解为非列表上下文可能会令人困惑)至少自 2004以来大部分时间在usenetunix.SE上讨论在类似 Bourne 的 shell 中不引用扩展的影响的文章。我不记得之前有人要求澄清我的意思(我确实经常尝试举例说明这种情况

我没有在任何 shell 语言的正式规范中使用它,这只是帮助向其他人解释 shell 行为的英文文本。

这不是官方术语,尽管这显然是受perl官方(在文档中)术语的启发。我不知道其他人是否在我之前在 Unix shell 的上下文中使用过这些(尽管他们很可能这样做了),但肯定有人从那以后使用过。我不主张所有权。

列表上下文(至少当我在我使用过的上下文中使用它时)仅表示 shell 需要任意数量元素的上下文。虽然标量/非列表/字符串上下文将是只需要一个(或单个字符串/标量,如果需要)的地方,例如perl. 在大多数类似 Bourne 的 shell 中,这些列表上下文是:

  • 简单的命令参数(如)echo elements
  • for i in elements
  • array=(elements)(和变体+=

一些 shell 有更多类似的东西:

  • cmd < elementszsh其中做类似的东西(如,但)。cat -- elements | cmdnl < *.txtnl < {foo,bar}.txtnl < foo.txt < bar.txt
  • cmd > elements(以及带有>| >>...的变体)zsh其中执行类似于cmd | tee -- elements
  • elements() { code; }inzsh一次定义一个或多个函数(如果元素解析为空列表,则什么也不定义(尽管文字() { echo x; }匿名函数))。
  • compound=(foo=(elements) elements)或等等。matrix=((elements) (elements))ksh93
  • 等等。

在这些上下文中,通常情况下,glob 会被扩展,如果您不想将 split+glob(或者只是空删除,zsh除非您启用shwordsplit/ globsubstsh-compatibility 选项)应用于它们,则需要引用您的扩展。

举例来说,如果你替换元素*.txt在上面的例子中,*.txt将扩展到当前目录txt文件的列表。

如果您正在寻找 POSIX 规范中的等效项,请查找扩展 glob 的上下文。POSIX 至少在一个实例中将其称为将执行字段拆分上下文(在我向 Austin 小组提出与之前的措辞有关的问题后,实际更改的措辞)。当然,该措辞对于回答有关在何处执行字段拆分的问题并不是很有用。

标量上下文将是其他情况下。

scalar=*.txt
case *.txt in...
[[ -f *.txt ]]
Run Code Online (Sandbox Code Playgroud)

*.txt无法扩展,因为 shell 只需要一个字符串。

作为一个警告/限制,这些条款不干净捕获在发生什么cmd > *cmd > ~(N)patterna=(); b=; c=(a b); d=*; IFS=:; e=a:b; cmd 1> "${a[@]}" 2> $b 3> "${c[@]}" 4> $d 5> $e在壳状bash/ yash(在不POSIX模式), ksh88(使用set -A而不是var=(...)语法)或ksh93(仅当互动与一些),其中可以看出作为另一个列表上下文,除了只需要一个包含一个元素的列表(对于某些情况,拆分和通配符的工作方式不同)。


归档时间:

查看次数:

572 次

最近记录:

7 年,6 月 前