我已经多次看到“列表上下文”和“字符串上下文”的使用。
我知道并理解在 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
表达式中,所以它是“(双引号)字符串上下文”。
“列表”在“列表上下文”中所指的是任何人的猜测,没有像这样的明确定义的模型。是主词表吗?或者代表一个单词的块列表?
由于您引用的大多数事件都是我自己写的,我觉得我必须在这里给出答案,尽管我主要是转述@Gilles。
至少自 2004年以来,我一直在使用列表上下文与标量/非列表上下文(比字符串上下文更好,如果不被理解为非列表上下文可能会令人困惑)至少自 2004年以来大部分时间在usenet或unix.SE上讨论在类似 Bourne 的 shell 中不引用扩展的影响的文章。我不记得之前有人要求澄清我的意思(我确实经常尝试举例说明这种情况)
我没有在任何 shell 语言的正式规范中使用它,这只是帮助向其他人解释 shell 行为的英文文本。
这不是官方术语,尽管这显然是受perl
官方(在文档中)术语的启发。我不知道其他人是否在我之前在 Unix shell 的上下文中使用过这些(尽管他们很可能这样做了),但肯定有人从那以后使用过。我不主张所有权。
列表上下文(至少当我在我使用过的上下文中使用它时)仅表示 shell 需要任意数量元素的上下文。虽然标量/非列表/字符串上下文将是只需要一个(或单个字符串/标量,如果需要)的地方,例如perl
. 在大多数类似 Bourne 的 shell 中,这些列表上下文是:
echo elements
for i in elements
array=(elements)
(和变体+=
)一些 shell 有更多类似的东西:
cmd < elements
在zsh
其中做类似的东西(如,但)。cat -- elements | cmd
nl < *.txt
nl < {foo,bar}.txt
nl < 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
/ globsubst
sh-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)pattern
或a=(); 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 次 |
最近记录: |