【问题标题】:What is a list in Bash?什么是 Bash 中的列表?
【发布时间】:2019-03-24 20:32:49
【问题描述】:

我在这里搜索了一个类似的问题,但令人惊讶的是找不到任何问题。

在 GNU bash 中,有一个(构造?结构?数据类型?)称为“arrays”。数组在 bash 文档中有很好的记录,所以我认为我了解基础知识。

但突然,在文档中也出现了“列表”一词。例如,在谈论filename expansion时使用它(重点是我的):

如果出现这些字符之一,则该词被视为一个模式,并替换为按字母顺序排列的与该模式匹配的文件名列表(请参阅模式匹配)。

因此,我有三个问题:

  1. 这里的“列表”是什么意思?
  2. 它的用法和for loop description的意思一样吗?
  3. 我不知何故迷失在 bash 的空白世界中。如果这个“列表”是一个独立于数组的概念(我认为),那么在涉及空格和IFS 时是否会对其进行特殊处理,或者与数组的处理方式相同?

another use of the "list" term 在谈论一个或多个管道的序列时,但我知道它很可能意味着不同类型的列表。


更新

  1. 因为我看到这种“列表结构”的工作方式与数组的工作方式非常相似——它们之间有什么区别?

更新 2

  1. 当“列表”优先于数组时,哪些用例是首选?例如,让我们比较一下。让我们创建两个文件:

    $ touch file1.txt file2.txt

说到列表,我可以做到以下几点:

$ A=*.txt ; echo $A
file1.txt file2.txt
$ 

当涉及到数组时,我可以做到以下几点:

$ B=(*.txt) ; echo ${B[@]}
file1.txt file2.txt
$ 

虽然这两个结果完全相同,但是否存在数组和列表返回不同结果的情况?


更新 3

我可能会混淆某些东西,因为在上面的示例中,它似乎是一个“包装”在数组中的列表。不知道有没有影响。

【问题讨论】:

  • 在更新 2 中,它们只是相同的,因为您有两个不包含空格的文件名。尝试创建一些确实在其名称中包含空格的文件,然后比较 printf '%s\n' $Aprintf '%s\n' ${B[@]}printf '%s\n' "$A"printf '%s\n' "${B[@]}"
  • 谢谢,@chepner。我看到还有一点是用什么工具来展示的。这符合我对从我的最后第二条评论到 codeforester 答案的列表的理解,即 Bash 是为了 treat 某些东西作为一个列表,而不是 define 作为列表的东西。 - 顺便说一句,好吧,已经有一段时间了,所以在你发表评论之后,我不得不回忆所有这些线程。但很高兴认识到我已经(几乎)理解了它。 ;)

标签: arrays bash list shell


【解决方案1】:

Bash 中没有称为 list 的数据类型。我们只有数组。在您引用的文档中,术语“列表”并不指数据类型(或任何技术) - 它仅表示文件名序列。

但是,就顺序循环而言,glob expansions 的工作方式与数组元素非常相似:

for file in *.txt; do          # loop through the matching files
                               # no need to worry about white spaces or glob characters in file names
  echo "file=$file"
done

相同
files=(*.txt)                  # put the list of matching files in an array
for file in "${files[@]}"; do  # loop through the array
  echo "file=$file"
done

但是,如果您要对文件名进行硬编码,则需要使用引号来防止 word splitting 和通配符:

for file in verycramped.txt "quite spacious.txt" "too much space.txt" "*ry nights.txt"; do ...

files=(verycramped.txt "quite spacious.txt" "too much space.txt" "*ry nights.txt")
for file in "${files[@]}"; do ...

在此处阅读有关分词的更多信息:

【讨论】:

  • 换句话说,它只是在英语意义上用来表示一系列项目,而不是在任何技术意义上。
  • C 语言在声明中具有说明符限定符列表、函数参数列表、宏中的替换标记列表:这些都不是 C 程序中的数据结构。 “列表”这个词只是非正式地使用。
  • 另外,修改帖子并在回答后添加更多问题不是一个好习惯。
  • codeforester,我已经阅读了它们(也许太快了?)。请原谅我的不理解。他们似乎回答了我的其他几个问题,尤其是关于空格的问题;它们非常有帮助,但是我要问的问题是关于“列表”的概念,而这些文章中的任何一篇都没有回答这些问题(或者至少我在那里看不到)。感谢您对更新的澄清。但是,我这样做是因为我认为其他用户将能够看到我的疑问;他们只是从前三个问题中澄清了我的疑问。
  • POSIX 没有根据实现细节来描述变量,而是描述操作及其结果:编程模型。变量看起来很像字符串。 shell 程序员看不到它们是如何存储的;你必须阅读你正在使用的 shell 的源代码。 Bash 可能与 zsh、pdksh、dash 等不同地表示它们,但可移植脚本的行为方式相同。
【解决方案2】:

术语“列表”实际上并不是 bash 中的特定技术术语;它在语法中用于指代一系列命令(例如for循环的主体,或脚本的内容),这种用法已经出现在程序结构的文档中,但这是一个非常特定类型的列表。

在您询问的上下文中,我会说“列表”是一个 ,由任意数量(包括 0)的 shell 单词组成。单个命令的参数就是这样一个列表。

反过来,你可以用另一种语言将其称为单个字符串。通常,当您键入命令行时,它会被$IFS 中列出的字符(通常是空格,即空格和水平制表符)分隔成单词,但是您可以通过任何各种引用机制来避免这种情况,从而创建包含 IFS 字符的 shell 词。

如果您希望在 shell 参数中存储一个列表,该参数必须是一个 数组;在这种情况下,列表中的每个单词都成为数组的一个元素。例如,传递给命令的参数列表在默认数组中可用,可通过$ 访问,后跟在命名数组引用中方括号之间的索引,例如"$@" 用于返回列表的所有元素,"$0" 用于第一个元素(即命令名称)等。

当数组扩展回单词列表时,您有三个选项;无论内容如何,​​数组的元素都可以保持原来的状态("$@");它们可以连接在一起,用空格连接成一个大的单个 shell 字 ("$*"),或者它们可以先连接成一个大字符串,然后使用通常的 IFS 分隔符规则重新解析成单词 ($@$* 不带引号)。

除了像mapfile(又名readarray)这样的一些内置函数,bash 对数组没有太多支持。例如,环境只能包含字符串,所以不能export 一个数组。您不能将数组传递给函数 as 数组,尽管您当然可以使用数组的值(或数组的切片)作为(部分或全部)参数列表传递给一个函数。您还可以将数组的 name 传递给函数,然后该函数可以使用名称引用和eval 在其调用方范围内操作该数组,但与所有机制一样任何语言的词法范围,这通常被认为是不好的做法。当然,函数不能返回数组,但是 bash 函数只能返回单字节数字退出代码。它可以输出文本,但该文本是非结构化的;如果调用者使用命令或进程替换捕获它,则由调用者自行解析文本,例如为每一行输出创建一个包含一个元素单词的数组,这是mapfile/@ 的默认行为987654335@.

无论如何,重点是,在这种情况下,列表是值,而数组是存储列表值的容器。从技术上讲,shell 参数(也称为“变量”)可以是数组,并且作为数组,它们可以保存列表;它们不能成为列表,而且引用“数组值”也没有任何意义。但非正式地,“数组”和“列表”经常互换使用;这就是懒惰人类的天性和贝壳的流动性。

【讨论】:

  • 马克里德,感谢您的回答。我的理解现在更大了。所以,用我自己的话来说——请确认与否:*.txt 产生了一个“列表”,但它是人类意义上的“列表”,是吗?通过 bash,它被视为一个“字符串”(在 任意 意义上),它将由 bash 在特定情况下知道的字符(空格、制表符、换行符、冒号、斜杠)分割等等。)?所以,总而言之,你的意思是一个“值”==一个“字符串”,任意理解? (顺便说一句,我现在有关于你提到的$@$* 的新问题,但这超出了关于“列表”的主要问题的范围。)
  • 好吧,在这种情况下,*.txt 只“产生” bash 导致它产生的东西,所以谈论它“产生” bash 然后解析的东西是没有意义的。 Bash 解析你输入的命令行;如果这包括任何引号之外的文字 5 字符序列 *.txt,它将将该序列替换为与该模式匹配的所有文件名的列表。现在我们在这里讨论的是 shell 术语中的单词列表,它是 bash 记忆中的实际工件,而不仅仅是人类列表。
  • 好的。我认为重点是我仍在考虑作业中的“列表”。而这种想法是错误的。我在另一个stackoverflow线程中读到(不记得确切的位置),赋值中的这样一个字符序列被视为一个值,就像你说的那样,即我理解的“字符串”。 仅当 bash 读取此变量的值,然后将其拆分等时,它才被视为列表。是真的吗?
  • 是的; A=*.txt 是一个简单的字符串赋值。在 shell 术语中,它导致 $A 包含一个单词。完成该分配后,shell 将两个命令行 ls *.txtls $A 视为完全相同。在每种情况下,您只键入两个 shell 字,但实际传递给 ls 的字数取决于目录的内容。另一方面, A=(*.txt) 将在您进行分配时查阅目录;那么 A 是一个包含匹配文件名列表的数组,即使您随后删除它们 ls "${A[@]}" 也会将所有它们作为参数传递给 ls
  • 即使是数组实际上也只是管理单独变量的语法糖,每个变量都有一个字符串值。任何地方都没有数组
【解决方案3】:

bash 中的列表是由管道分隔的特定表达式序列。来自man bash,例如

Lists

   A list is a sequence of one or more pipelines separated by one of the 
   operators ;, &, &&, or ||, and optionally terminated by one of ;, &, or 
   <newline>. 

   Of these list operators, && and || have equal precedence, followed by 
   ; and &, which have equal precedence.

   A sequence of one or more newlines may appear in a list instead of a 
   semicolon to delimit commands.

   If a command is terminated by the control operator &, the shell 
   executes the command in the background in a subshell. The shell does 
   not wait for the command to finish, and the return status is 0. 
   Commands separated by a ; are executed sequentially; the shell waits 
   for each command to terminate in turn. The return status is the exit 
   status of the last command executed.

   AND and OR lists are sequences of one of more pipelines separated by 
   the && and || control operators, respectively. AND and OR lists are 
   executed with left associativity. An AND list has the form

          command1 && command2

   command2 is executed if, and only if, command1 returns an exit status 
   of zero.

   An OR list has the form

          command1 || command2

   command2 is executed if and only if command1 returns a non-zero exit 
   status. The return status of AND and OR lists is the exit status of 
   the last command executed in the list.

List 用于形成Compound Commands(参见man bash)。

在谈论序列时,“列表”一词还有另一种用法 一个或多个管道,但我知道这很可能意味着 不同类型的列表。

两者:

$ A=*.txt ; echo $A

$ B=(*.txt) ; echo ${B[@]}

在 bash 中技术上是 Lists

【讨论】:

  • DavidCRankin,感谢您的回答。我现在看到 bash 中的“列表”一词比人们想象的更含糊。需要明确的是,我宁愿询问*.txt 的结果,例如在作业中,而不是整行。但是,我认为你确认了“列表”的感觉非常好。 +1
猜你喜欢
  • 2013-05-17
  • 2013-11-26
  • 2012-05-12
  • 2011-04-23
  • 2016-06-19
  • 1970-01-01
  • 2010-09-09
  • 2012-09-06
  • 2013-07-15
相关资源
最近更新 更多