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 / 问题 / 668558
Accepted
Nick Bull
Nick Bull
Asked: 2021-09-12 01:48:25 +0800 CST2021-09-12 01:48:25 +0800 CST 2021-09-12 01:48:25 +0800 CST

为什么 zsh printf 不尊重八进制表示法?

  • 772
sh -c 'printf "%d " 024'
bash -c 'printf "%d " 024'
zsh -c 'printf "%d" 024'

以上输出20 20 24。为什么 zsh 不尊重八进制表示法?有没有办法改变这个?

zsh printf
  • 3 3 个回答
  • 307 Views

3 个回答

  • Voted
  1. Best Answer
    Stéphane Chazelas
    2021-09-13T03:28:06+08:002021-09-13T03:28:06+08:00

    zsh不是 POSIX shell,它是在 POSIX 规范sh发布之前编写的,从 ksh、csh、tcsh、rc 中获取特性和语法,并添加了许多自己的。它的语法在很大程度上类似于 Korn,但这并不意味着它与 Korn shell 完全兼容。无论如何,它不是也不打算成为 sh 语言的 POSIX 兼容解释器(至少不是在其默认模式下)。

    然而,它有许多仿真模式(csh、ksh 和 sh(以前尝试遵循 SysV sh,现在遵循 POSIX sh)),可用于提高与其他 shell 的兼容性并解释为它们编写的代码。这意味着它可以有自己的语法,与 sh 或任何其他 shell(如 csh、rc、fish、perl、python...)的语法不同,并且仍然能够解释为 sh 编写的代码。

    如果调用为sh, csh, or ksh(或任何以s(或bBourne)c或k) 开头的东西,或在带有 的较新版本中调用--emulate sh/ksh/csh,它将进入相应的仿真模式,但这不是您通常使用的方式。要解释sh脚本,您将运行sh,而不是zsh.

    当你想在zsh中解释sh代码时,你宁愿run emulate shinsidezsh来切换仿真模式,你也可以在仿真中运行解释。shemulate sh -c 'some code'some codesh

    所以,在zsh:

    emulate sh -c 'printf "%d\n" 024'
    

    将以printf更 POSIX 的方式运行。

    至于printf,大约在 1986 年,Research Unix 第九版(来自 AT&T Research/Bell Labs,未广泛使用)中首次出现了一个实用程序,以使用libc 函数printf获得与 C 中可用的相同文本格式化 API 。printf

    虽然C它采用格式第一个参数作为指向以 NUL 分隔的字节数组和不同类型(指针、整数、双精度...)的额外参数的指针,但可执行文件只能将参数作为字符串。因此,要格式化一个数字,例如%d,需要给它一个数字的文本表示形式,并将其转换回二进制整数printf并将其转换回文本以进行输出。

    在V9的原始实现中,printf识别出与 C 语言中相同的数字(dec -123、+123、 octal 0123、 hex 0x123、 float 1.2e-2、 even 'x'or "foo"(其中使用的第一个字符的值))。

    SVR4(源自 V7)也有一个非常愚蠢的printf实用程序:

            printf(fmt, argv[2], argv[3], argv[4],  argv[5],
                            argv[6], argv[7], argv[8], argv[9],
                            argv[10], argv[11], argv[12], argv[13],
                            argv[14], argv[15], argv[16], argv[17],
                            argv[18], argv[19], argv[20]);
    

    所以它只对%s-type 格式化有用,因为printf()它只给出了指向字符串参数的指针。

    POSIX.2(写于 80 年代后期(大部分)闭门造车并于 1992 年发布(当时不可免费获得)),指定了一个printf命令。由于该echo实用程序非常不便携且不可靠,因此非常需要替代方案。出于某种原因,他们没有选择ksh'print内置,而是指定了一个printf主要基于 V9 实现的实用程序,并在将字符串转换为数字时参考了 C 语言。

    ksh88,POSIXsh规范所基于的 shell 从来没有printf内置函数(也没有它的 pdksh 克隆)。它有自己的print内置函数作为echo. 在 ksh93 中添加了一个-f选项 for以及.printprintfprint -f

    在 ksh 中,大多数将数字作为输入的内置函数或构造都将接受任何算术表达式,而不仅仅是数字常量。所以在 ksh93

    printf '%d\n' '1 + 1'
    

    会打印2。

    在早期版本中,printf '%d\n' 010将打印 10,而不是 8。

    在 ksh shell 算术表达式中,最初,带有前导 0 的数字不被视为八进制,因为在 shell 中,处理 0 填充的十进制数字(如日期/时间、文件名)比处理更常见八进制数。

    然而,POSIX 规范确实要求将那些被视为大多数 shell 忽略的八进制(因为标准所基于的 shell 的原始实现没有)。然而,在PASC 解释请求使其更清晰之后,大多数 shell 开始改变它们的行为(包括 ksh93和zsh,尽管这已被恢复),造成了很大的痛苦。

    如果您查看ksh93 的发布历史记录,您会注意到以 0 为前缀的数字作为八进制的处理一直处于开启和关闭状态。即使在今天,你会发现算术表达式中的 010 在((...))or中是 8 $((...)),但在大多数其他地方,包括let '...'、array[...]和[[ ... -eq ... ]]...中都是 10 printf。set -o posix使它在大多数地方变为 8,一个值得注意的例外是......printf再次。

    由于 zsh 从未声称自己是 POSIX shell,它只是在 2000 年添加了一个新选项 ( octal_zeroes),在sh仿真中启用,但不是在其他情况下。

    2001 年晚些时候添加了一个printf内置函数,最初strtod()用于将文本转换为数字,因此将前导 0 的数字视为八进制,但后来更改为接受 ksh93 中的任何算术表达式,因此受octal_zeroes选项影响,并允许更多的数字格式,例如0b10010, ksh - 风格的任意基数 ( 12#A001, 2#10010...), 1_000_000...

    因此,在 中zsh,要将八进制数传递给printf,选项有:

    • 模拟sh并使用前导 0:emulate sh -c 'printf %d 024'
    • 设置octalzeroes选项:set -o octalzeroes; printf %d 024
    • 仅在本地范围内相同:((){ set -o localoptions -o octalzeroes; printf %d 024; }此处为匿名函数)。
    • 使用8#oooo公认的符号:printf %d '8#24'
    • 禁用printf内置,并假设系统的printf实用程序在这方面是 POSIX 兼容的:disable printf; printf %d 024.
    • 调用该独立的其他方法printf:(command printf %d 024不在sh仿真中),=printf %d 024(不在sh仿真中)。
    • 5
  2. Random832
    2021-09-12T02:17:41+08:002021-09-12T02:17:41+08:00

    用于command printf ...运行标准 printf 实用程序。zsh 的 printf 有自己的与 POSIX 标准冲突的参数解释, %d 将参数解释为算术表达式,因此您可以将八进制值转换为printf %d '8#24'.

    • 1
  3. schily
    2021-09-12T02:21:19+08:002021-09-12T02:21:19+08:00

    默认情况下,zsh 不符合 POSIX 标准,而且偏差并不小。

    这是使用 zsh 的一般问题。

    尝试:

    zsh --emulate sh -c 'printf "%d\n" 024'
    

    它会打印 20

    但请注意,这仅适用于最新zsh版本。

    如果您喜欢一种甚至适用于旧zsh版本的方法,那么有一种方法可以做到这一点。创建一个$HOME/.zshenv包含以下内容的文件:

    if [ -n "$ZSH_EMULATION" ]; then
        emulate "$ZSH_EMULATION"
    fi
    

    如果你有那个文件,你可以调用:

    ZSH_EMULATION=sh zsh -c 'printf "%d\n" 024'
    

    这将适用于任何版本的zsh.

    ZSH_EMULATIONBTW:在评论中讨论后已经介绍了当前的文本。

    • 0

相关问题

  • 什么情况下路径中最先找到的可执行文件不会被使用

  • 符号链接所有点文件和目录

  • 如何在`zsh`中增加一个动态命名的变量

  • 为什么我不能在 zsh 中定义一个名为 path 的只读变量?

  • 如何使用 Bash 内置的“printf”在源中包含颜色的列中输出?

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