最近,我在计算机上设置了Microsoft的Windows Linux子系统。它只是模仿Linux环境和东西。基本上是Cygwin,但与底层Windows系统的连接要好一些。从Cygwin切换到WSL之后,我遇到了一个问题。我不知道它是否特定于Windows的实现,但这在Cygwin中不会发生。
为了更快地捕获代码中的错误,我开始使用bash的set -u选项,该选项使外壳“在替换时将未设置的变量视为错误”。否则,bash在扩展它们时会将未设置的变量视为设置为空字符串的变量。
但是,这对数组有一个奇怪的意外结果(至少在WSL上):
Me@Computer:~$ set -u
==>
Me@Computer:~$ declare -p array
==> bash: declare: array: not found
Me@Computer:~$ array=( )
==>
Me@Computer:~$ declare -p array
==> declare -a array='()'
Me@Computer:~$ echo "${array[@]}" # Expands to "echo" (with 0 args), right?
==> bash: array[@]: unbound variable # Wrong! wtf, bash??
Run Code Online (Sandbox Code Playgroud)
从的输出中可以看到declare -p array,bash 确实识别出数组为空和数组未设置之间的区别-直到需要真正对其进行扩展时,bash才适合。我知道bash 特别对待@and *变量,甚至在引用时也是如此,因此我尝试了很多东西。无效:
Me@Computer:~$ echo "${array[@]}"
==> bash: array[@]: unbound variable
Me@Computer:~$ echo "${array[*]}"
==> bash: …Run Code Online (Sandbox Code Playgroud) 为了对Idris进行一些练习,我一直试图将各种基本的代数结构表示为接口。首先,我想到的组织事物的方式是使给定接口的参数成为集合并对其进行各种操作,而方法/字段则证明各种公理。例如,我正在考虑Group这样定义:
Group (G : Type) (op : G -> G -> G) (e : G) (inv : G -> G) where
assoc : {x,y,z : G} -> (x `op` y) `op z = x `op` (y `op` z)
id_l : {x : G} -> x `op` e = x
id_r : {x : G} -> x `op` e = x
inv_l : {x : G} -> x `op` (inv x) = e
inv_r : {x : …Run Code Online (Sandbox Code Playgroud) 编辑:这已被确认是一个错误并将被修复:https : //lists.gnu.org/archive/html/bug-bash/2018-03/msg00055.html
所以我在搞砸 bash 的间接功能,namerefs。我以为我已经掌握了它的窍门,但是当我试图弄清楚如何将 namerefs 转换为常规变量时,我遇到了一些让我困惑的事情。
这是来自man bash:的相关段落:
declare -n为每个名称指定 nameref 属性,使其成为对另一个变量的名称引用。另一个变量由 name 的值定义。除了使用或更改 -n 属性本身的那些引用、赋值和属性修改之外,所有对 name 的引用、赋值和属性修改都是在 name 值引用的变量上执行的。
因此,假设您想取消设置 nameref——不是它指向的变量,而是变量本身。您不能只说unset foo,因为这实际上会取消设置foo指向的任何内容;相反,您必须将其设为常规变量,然后取消设置:
$ declare -p
$ foo=bar; bar='hello world'
$ declare -p
declare -- foo="bar"
declare -- bar="hello world"
$ declare -n foo; declare -p # 'foo' is now a nameref
declare -n foo="bar"
declare -- bar="hello world"
$ declare +n foo; declare -p # …Run Code Online (Sandbox Code Playgroud) 在时,我还不清楚在哪个陷阱上继承bash。联机帮助页上说:
当执行除内置函数或shell函数以外的简单命令时,将在单独的执行环境中调用该命令[...] [T]由shell捕获的陷阱将重置为从shell的父级继承的值,并陷阱被shell忽略的被忽略[。]
稍后,它说子shell的行为方式相同。
我认为这对我来说很有意义。这听起来像一颗炮弹取消设置一个陷阱,即得到任何子shell想起和诸如此类的东西,如果一个壳,同时设定一个陷阱,那被遗忘。我不知道为什么要做出这种设计选择,但是至少我认为我了解发生了什么。
但有关命令什么是内建命令或shell的功能呢?两者的行为是否有所不同(就陷阱继承而言)?我在手册中找不到完整的说明,据我所知,一切正常。似乎它们通常是从父级继承的,但是有像ERR和这样的异常RETURN,每个异常仅在使用某些shell选项时才由函数继承。
我的问题是:
陷阱继承对内置函数和函数起作用的典型方式是什么?例如,关于设置陷阱还是不设置陷阱,在大多数命令看来都是如此吗?
所有函数和内建函数的行为方式都一样吗?(请不要告诉我每个内置函数都有一套单独的规则...)
有什么例外?即,默认情况下哪些信号的行为不同,哪些功能可以通过shell选项和其他功能更改其默认行为?我知道ERR和RETURN,但是还有其他人吗?尽我所能,在任何地方都找不到一个简单的列表。
函数或内建函数何时可以影响父级的陷阱?trap - SIGSPECvs. 如何trap '' SIGSPEC发挥作用?
谢谢!
PS:我正在使用GNU bash版本“ 4.4.19(1)-发行版”。
bash ×3
shell ×2
arrays ×1
code-cleanup ×1
idris ×1
indirection ×1
interface ×1
math ×1
type-theory ×1
types ×1
unset ×1