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 / 问题 / 782661
Accepted
dr_
dr_
Asked: 2024-08-28 21:08:35 +0800 CST2024-08-28 21:08:35 +0800 CST 2024-08-28 21:08:35 +0800 CST

算术扩展中的“$var”和“var”有什么区别?

  • 772

Bash 接受以下两种语法:

FOO=$(($BAR + 42))

和

FOO=$((BAR + 42))

哪一个是正确的/最可移植的/不容易出错?还是两者都同样有效?

bash
  • 1 1 个回答
  • 352 Views

1 个回答

  • Voted
  1. Best Answer
    ilkkachu
    2024-08-28T21:29:11+08:002024-08-28T21:29:11+08:00

    这取决于您想做什么,但您应该首先验证算术环境中使用的任何输入(见结尾)。


    参数扩展(例如$var和命令替换)是在解析算术表达式本身之前完成的。(*) 该扩展与算术语法无关,因此$var您可以随意处理它。

    另一方面,不带$符号的var是在解析算术表达式后进行求值的,并且必须是可以求值的东西。但在 Bash 中,它可以是一个完整的表达式(**)。

    (* 除了一些 shell 有例外,这样$(( a[$key] = 1 ))即使key是也能使类似的操作有效]。)

    (** 大多数其他 shell 也允许在变量中使用完整的表达式,但 Debian 和 Ubuntu 上的 Dash 除外/bin/sh。)


    因此,例如$var如果变量为空,使用会产生语法错误,而使用var它将被视为零。

    $ echo $((10 - var))
    10
    $ echo $((10 - $var))
    bash: 10 - : syntax error: operand expected (error token is "- ")
    

    10 - $var产生的只是10 -无效的表达式。(这不会发生在您的示例中,$BAR + 42因为+ 42是有效表达式。)

    另一方面,您可以使用$var包含部分表达式:

    $ op=+; echo $(( 1 $op 2 ))
    3
    

    使用var,您只能包含完整的子表达式(在 Bash 中):

    $ var=1+2
    $ echo $(( 10 *  var  ))
    30
    

    但请注意,$var在这里使用会改变评估的顺序!

    $ var=1+2
    $ echo $(( 10 * $var  ))
    12
    

    这里,首先扩展变量,得到10 * 1+2,然后使用正常算术规则进行解析,先乘法,与相同(10 * 1) + 2。

    $(( 10 * var ))没有美元符号实际上会在变量周围放置隐式括号,因此有点像$(( 10 * (1+2) ))。

    作为将变量解释为完整表达式的一部分,如果一个变量命名了另一个变量,Bash 将追踪名称链:

    $ one=two two=three three=four four=4; echo $(( one ))
    4
    

    没有美元符号的形式仅适用于实际命名的变量。如果您想使用位置参数$1、$2...或算术中的特殊变量(如$#或)$?,则必须使用美元形式。(这应该是相当明显的,但仍然如此。)

    另请参阅Bash:算术扩展、参数扩展和逗号运算符,了解另一个有趣的区别。


    虽然你应该像往常一样引用扩展,但你不需要在算术表达式中引用变量扩展,这样做实际上会破坏许多 shell。所以,请使用"$(( ...))",但不要$(( "$foo" ))(例如 zsh 在 上发出i=123; echo $(( "$i" )))


    无论如何,请注意,无论哪种情况,Bash 的算术评估都容易受到简单的命令注入攻击,如下所示:

    $ var='a[$(date >&2)]'
    $ echo $(( $var * 10 ))
    Wed Aug 28 16:25:57 EEST 2024
    0
    $ echo $((  var * 10 ))
    Wed Aug 28 16:26:49 EEST 2024
    0
    

    这意味着如果你从外部获取值,在算术上下文中使用它们之前,你应该先验证它们。如果在验证之后你知道你得到的是一个简单的数字,那么使用哪种形式就无关紧要了。

    (这在 Dash 中不会发生,因为它不支持数组,而 zsh 似乎不受此影响。)

    • 10

相关问题

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

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

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

  • `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