AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / unix / 问题 / 677909
Accepted
db-inf
db-inf
Asked: 2021-11-18 03:01:55 +0800 CST2021-11-18 03:01:55 +0800 CST 2021-11-18 03:01:55 +0800 CST

对数组元素进行一元测试 -v

  • 772

在 bash 中,带有一元测试的条件表达式-v myvariable测试变量myvariable是否已设置。请注意,myvariable不应通过以美元为前缀来扩展它,所以不是 $myvariable. 现在我发现对于数组元素,条件表达式-v myarray[index]也可以很好地工作,而无需完整的扩展语法${myarray[$index]}。尝试这个:

    myarray[2]=myvalue
    for i in 1 2 3
    do
        [ -v myarray\[i] ] && echo element $i is set
    done

(注意转义\[以防止通配符,作为使用引号的替代方法)

给出所需的输出:

    element 2 is set

问题 这种行为是否可以安全使用,也就是这种记录在案的行为吗?

附录 阅读 Stéphane Chazelas 的答案https://unix.stackexchange.com/a/677920/376817后,我扩展了我的示例:

    myarray[1]=val myarray[2]=val myarray[3]=val myarray[4]=val myarray[5]=val myarray[6]="" myarray[2]=""
    unset myarray[3] myarray[4] myarray[5]
    touch myarray4 myarrayi
    myarray4=val myarrayi=val

然后

    for i in {0..7}; do [ -v myarray\[i] ] && echo element $i is set; done

给

    element 1 is set
    element 2 is set
    element 6 is set

不引用或转义索引表达式[i]:

    for i in {0..7}; do [ -v myarray[i] ] && echo element $i is set; done

给

    element 0 is set
    element 1 is set
    element 2 is set
    element 3 is set
    element 4 is set
    element 5 is set
    element 6 is set
    element 7 is set

与变量myarrayiunset 相同:

    unset myarrayi
    for i in {0..7}; do [ -v myarray[i] ] && echo element $i is set; done

给

    %nothing%

最后将索引扩展为$i(仍然没有引用或转义括号):

    for i in {0..7}; do [ -v myarray[$i] ] && echo element $i is set; done

它给

    element 1 is set
    element 2 is set
    element 4 is set

因为

    ls -l myarray*

节目

    -rw-rw-r-- 1 me us 0 nov 17 15:37 myarray4
    -rw-rw-r-- 1 me us 0 nov 17 15:37 myarrayi
bash array
  • 1 1 个回答
  • 402 Views

1 个回答

  • Voted
  1. Best Answer
    Stéphane Chazelas
    2021-11-18T04:14:14+08:002021-11-18T04:14:14+08:00

    在bash中,您可以执行以下操作:

    [ -v 'a[2]' ]
    

    或者

    [[ -v a[2] ]]
    

    要测试是否设置了索引 2 的数组元素或键“2”的关联数组元素(即使是空字符串),但请注意:

    • 使用[(aka test) 命令时,您需要引用[and]字符,因为它们是通配符。由于[它只是一个普通命令,因此它的解释方式与任何其他普通命令一样,因此a[2]in 的[ -v a[2] ]扩展方式与在ls -d a[2]or中的方式相同unset a[2]。如果a2在当前工作目录中调用了一个文件,a[2]则会扩展到该文件。如果没有,但nullgloborfailglob被启用a[2]将分别扩展为空或给出错误。[[ ... ]]是一个特殊的结构,有自己的语法,所以不会有问题。

    • 对于关联数组(至少在我测试过的版本 5.1 中),如果要检查的键在$i变量中,则您希望[ -v 'a[$i]' ]or[[ -v 'a[$i]' ]]并且assoc_expand_once在较新版本中引入的选项bash 不启用。使用[ -v "a[$i]" ]or[[ -v a[$i] ]]不适用于$i包含]或反斜杠的某些值。在那里,这$是必须引用的。另请参阅如何在算术表达式中安全地使用关联数组?.

    • 仍然对于关联数组,请注意bash(与尝试复制的相反ksh93or bash)zsh不支持空键。如果你使用[[ -v 'a[$i]' ]]and$i是空字符串,你会得到一个错误。因此,要测试任意键值,请使用[[ -n $i && -v 'a[$i]' ]]or [ -n "$i" ] && [ -v 'a[$i]' ]。

    • 对于普通(稀疏)数组, in[ -v 'a[expr]' ]或[[ -v a[expr] ]],expr被评估为算术表达式。这就是为什么两者都i起作用$i。由于算术表达式可能会产生分配变量或运行任意命令的副作用,因此对$iused in的值[ -v 'a[i]' ]进行清理非常重要,否则您就有任意命令执行漏洞。正如在 bash/POSIX shells 中忘记引用变量的安全影响中bash所见, '[ -v lvalue ]对数组索引起作用的事实使得[ -f $file ](作者忘记引用的地方$file)成为 ACE 漏洞。

    • 在任何情况下,您始终可以使用[ -n "${var+set}" ]应用于(关联)数组元素的 Bourne/POSIX 方法[ -n "${a[$key]+set}" ](或关联数组支持(4.0(2009)或更高版本),并且可以跨外壳移植。

    • 请注意,[ -v var ]实际上与[ -v 'var[0]' ]. 就像在 ksh88 中一样,标量变量可以看作是数组索引为 0 的元素。

    • 要检查数组或关联数组是否有任何元素(或是否设置了标量变量),您也可以执行[ "${#a[@]}" -gt 0 ]or[ -v 'a[@]' ]或[ -v 'a[*]' ].

    • 要遍历稀疏数组的索引或关联数组的键,您可以执行以下操作:

      for key in "${!a[@]}"; do
        printf 'The element of key "%s" is set\n' "$key"
      done
      

      (这给出0了一个标量变量)。

    至于这是否记录在案:如果您运行info bash testor info bash '[',您会看到它遵循Bash 条件表达式(如内部使用[[ ... ]]的),其中的文档-v有:

    -v VARNAME
    如果设置了 shell 变量 VARNAME(已被赋值),则为真。

    虽然help test有:

     -v VAR         True if the shell variable VAR is set.
    

    可能是什么VARNAME(特别是如果允许数组成员)或者如果VARNAME引用一个不是标量变量的变量,它会做什么没有明确指定。但是考虑到a[x]在任何需要变量名的地方通常都允许这样做,并且几十年来一直如此,我们可以放心地假设它在未来仍将如此。

    如果您查看该官方文档的其他部分,您会发现它通常暗示在任何需要变量名称的地方(无论它被称为NAME、VAR、VARNAME还是更普遍的PARAMETER)varname[index]也被接受。例如,在unset它本身 ( info bash unset) 的文档中,没有提到unset 'array[i]',但在关于数组的部分中提到了它。

    源代码分发(发行说明)中的NEWS文件告诉我们,它test -v是在 bash-4.2(2011)中添加的,可能是受到 ksh93 的启发,不久之前在 ksh93t+(2009,在其自己的发行说明中提到了数组元素支持)

    F。 test//有一个新的变量一元运算符[,如果设置了`variable'则返回成功。[[-v

    在 4.3 中:

    二。test//二元运算符现在可以理解数组引用[。[[ -v variable

    在 5.1 中:

    X。test -v N现在可以测试是否设置了位置参数 N。

    您会发现CWRU/changelog在源代码分发中提到test -v array[@]或[[ -v array[$key] ]]用于关联数组,再次暗示该功能是有意的。

    将来可以做一些事情来解决上面提到的一些问题,这可能会使我提到的解决方法无效,例如需要引用$。

    • 11

相关问题

  • 通过命令的标准输出以编程方式导出环境变量[重复]

  • 从文本文件传递变量的奇怪问题

  • 虽然行读取保持转义空间?

  • `tee` 和 `bash` 进程替换顺序

  • 运行一个非常慢的脚本直到它成功

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    模块 i915 可能缺少固件 /lib/firmware/i915/*

    • 3 个回答
  • Marko Smith

    无法获取 jessie backports 存储库

    • 4 个回答
  • Marko Smith

    如何将 GPG 私钥和公钥导出到文件

    • 4 个回答
  • Marko Smith

    我们如何运行存储在变量中的命令?

    • 5 个回答
  • Marko Smith

    如何配置 systemd-resolved 和 systemd-networkd 以使用本地 DNS 服务器来解析本地域和远程 DNS 服务器来解析远程域?

    • 3 个回答
  • Marko Smith

    dist-upgrade 后 Kali Linux 中的 apt-get update 错误 [重复]

    • 2 个回答
  • Marko Smith

    如何从 systemctl 服务日志中查看最新的 x 行

    • 5 个回答
  • Marko Smith

    Nano - 跳转到文件末尾

    • 8 个回答
  • Marko Smith

    grub 错误:你需要先加载内核

    • 4 个回答
  • Marko Smith

    如何下载软件包而不是使用 apt-get 命令安装它?

    • 7 个回答
  • Martin Hope
    user12345 无法获取 jessie backports 存储库 2019-03-27 04:39:28 +0800 CST
  • Martin Hope
    Carl 为什么大多数 systemd 示例都包含 WantedBy=multi-user.target? 2019-03-15 11:49:25 +0800 CST
  • Martin Hope
    rocky 如何将 GPG 私钥和公钥导出到文件 2018-11-16 05:36:15 +0800 CST
  • Martin Hope
    Evan Carroll systemctl 状态显示:“状态:降级” 2018-06-03 18:48:17 +0800 CST
  • Martin Hope
    Tim 我们如何运行存储在变量中的命令? 2018-05-21 04:46:29 +0800 CST
  • Martin Hope
    Ankur S 为什么 /dev/null 是一个文件?为什么它的功能不作为一个简单的程序来实现? 2018-04-17 07:28:04 +0800 CST
  • Martin Hope
    user3191334 如何从 systemctl 服务日志中查看最新的 x 行 2018-02-07 00:14:16 +0800 CST
  • Martin Hope
    Marko Pacak Nano - 跳转到文件末尾 2018-02-01 01:53:03 +0800 CST
  • Martin Hope
    Kidburla 为什么真假这么大? 2018-01-26 12:14:47 +0800 CST
  • Martin Hope
    Christos Baziotis 在一个巨大的(70GB)、一行、文本文件中替换字符串 2017-12-30 06:58:33 +0800 CST

热门标签

linux bash debian shell-script text-processing ubuntu centos shell awk ssh

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve