Contents

POSIX指南

1. 概述

在本教程中,我们将了解 POSIX 是什么以及它为什么会出现。然后,我们将看看 POSIX 背后的一些历史以及它是如何演变的。之后,我们将介绍一些重要的 POSIX 标准。

最后,我们将看到完全或部分符合 POSIX 的操作系统。

2.什么是POSIX?

POSIX 代表便携式操作系统接口。它是 IEEE 为维护操作系统之间的兼容性而指定的一系列标准。因此,任何符合 POSIX 标准的软件都应该与其他符合 POSIX 标准的操作系统兼容

出于这个原因,我们在 Linux 和类 Unix 操作系统上使用的大多数工具的行为几乎相同。例如,如果我们使用ps命令,它在 OpenBSD、Debian 和 macOS 下的行为应该相同。

2.1. 历史

在信息时代的早期,程序员会为具有不同系统接口和环境的操作系统编写软件。因此,将软件移植到其他操作系统需要大量的调整和成本。

为了克服这个问题,POSIX 诞生了。POSIX 是原始 UNIX 的标准化,它于 1988 年回归,不仅解决不同 UNIX 变体之间的问题,还解决非 UNIX 操作系统之间的问题。

POSIX 的工作始于 1980 年代初期,旨在标准化快速发展的 UNIX 系统接口。它简明扼要地涵盖了各种系统。重要的 POSIX.1 标准成为国际公认的标准 ISO/IEC 9945-1:1990,而 POSIX.2 标准作为 IEEE Std 1003.2-1992 被国际公认。

2.2. POSIX 版本

POSIX 引用的标准系列称为 IEEE Std 1003. n-yyyyn可以替换为版本号,例如 IEEE Std 1003.1 。我们也可以将 IEEE Std 1003.1 称为 POSIX.1。POSIX.1 的当前版本是IEEE Std 1003.1-2017

POSIX 1003.1 是开发 POSIX 系列标准的基础标准,目前在 POSIX 保护伞下有 20 多个标准和草案。

POSIX.1 定义了应用程序的可移植性,以及 C 接口和系统服务的行为,用于基本任务,例如进程创建和终止、进程环境操作、文件和目录访问以及简单的 I/O。

另一方面,POSIX.2 描述了命令解释器、可移植 shell 编程、用户环境和相关实用程序。这两个标准都受到现有 UNIX 实践和经验的强烈影响。

3. POSIX 定义的标准

在本节中,我们将了解一些基本的 POSIX 标准。此外,我们可以使用The Open Group Base Specifications Issue 作为深入参考。

3.1. C API

POSIX 用 C 语言定义其标准。因此,程序可以在源代码级别移植到其他操作系统。尽管如此,我们也可以用任何标准化的语言来实现它。

POSIX C API 在 ANSI C 标准之上为多个方面添加了更多功能:

  • 文件操作
  • 进程、线程、共享内存和调度参数
  • 联网
  • 内存管理
  • 常用表达

函数的完整描述在 POSIX标头 中定义。

3.2. 一般概念

除了 C API,POSIX 还添加了编写程序的规则,例如指针类型初始化和并发执行的安全性。它还强制执行内存同步规则,例如限制已使用的内存修改。除此之外,它还说明了目录保护和文件访问的安全机制。

3.3. 文件格式

POSIX 定义了用于格式化我们在文件、标准输出、标准错误和标准输入中使用的字符串的规则。例如,让我们考虑输出字符串的描述:

"<format>", <arg1>, ..., <argN>

**格式可以包含常规字符、转义序列字符转换规范 。**转换规范指示提供的参数的输出格式,并以百分号为前缀,后跟参数类型。

例如,假设我们要输出一个包含今天日期的字符串。我们将使用printf 实用程序,因为它遵循 POSIX 文件格式标准:

$ printf "Today's Date: %d %s, %d" 18 September 2021
Today's Date: 18 September, 2021

该格式指定了三个转换规范:%d%s和*%d*。printf实用程序处理这些 转换规范并用参数替换它们。

3.4. 环境变量

环境变量是我们可以在环境文件中定义的变量,登录 shell 在成功登录时对其进行处理。按照惯例,变量名应仅包含大写字母和下划线。名称也可以包含数字,尽管 POSIX 标准不建议将数字放在名称的开头。

**对于每个环境变量,值只能是可移植字符集中 定义的字符串。**例如,我们可以为我们的基本用户目录定义环境变量,格式如下:

XDG_BASE_DIRECTORY="/home/user/"

我们可以随意命名环境变量,尽管我们应该避免使用与**标准实用程序 的环境变量冲突的名称来定义我们自己的环境变量。**此外,我们的一致性实现应该对环境变量名称区分大小写。例如,名称homeHome是两个不同的环境变量。

我们的实现应该尊重保留的环境变量:

  • COLUMN定义终端屏幕的宽度。
  • HOME定义用户主目录的路径名。
  • LOGNAME定义用户的登录名。
  • LINES定义了终端屏幕上用户的首选线路。
  • PATH为可执行文件定义二进制冒号分隔的路径。
  • PWD定义当前工作目录。
  • SHELL定义当前使用的 shell。
  • TERM定义终端类型。

3.5. 当地的

**语言环境定义了用户环境中使用的语言和文化惯例。**每个语言环境都由定义软件组件行为的类别组成,例如日期时间格式、货币格式和数字格式。

程序实现应符合与C 语言环境 相同的 POSIX 语言环境。程序实现应该利用当前定义的语言环境变量来保持连贯性。如果没有设置语言环境,则实现应指定其符合 POSIX 的语言环境

POSIX 标准为每个类别定义了以下环境变量:

  • LC_TYPE用于字符分类
  • LC_COLLATE定义字符的顺序
  • LC_MONETARY用于货币格式
  • LC_NUMERIC用于格式化数字
  • LC_TIME用于日期和时间格式
  • LC_MESSAGES用于程序消息,例如信息消息和日志

3.6. 字符集

字符集是字符的集合,由每个字符的代码和位模式组成。众所周知,计算机只理解二进制,所以一个字符集代表了计算机可以处理的符号。因此,我们需要一个符合 POSIX 定义的标准字符集。

POSIX 建议我们的实现应该至少包含一个字符集和一个可移植字符集 。字符集中的前八个条目应为控制字符 。POSIX 语言环境应包括至少 256 个来自可移植和不可移植字符集的字符。

3.7. 常用表达

正则表达式或 RE 是定义用于查找文本的搜索模式的字符串。标准 C 库实现 RE,并被awk、 sedgrep等程序用作后端。

符合 POSIX 的实现可以使用基本正则表达式 (BRE) 或扩展正则表达式 (ERE)。**BRE 提供用于搜索文本的基本符号,而 ERE 支持更多符号。**尽管高级文本操作实用程序也支持 ERE,但大多数符合 POSIX 的实用程序都严重依赖 BRE。

此外,一些要求适用于 BRE 和 ERE:

  • BRE 和 ERE 应该对以NUL字符结尾的字符串进行操作。
  • 文字转义序列换行符会产生未定义的结果。因此,我们的程序应该将它们视为普通字符。
  • POSIX 不允许在 RE 或要匹配的文本中使用显式NUL字符。
  • 默认情况下,我们的实现应该能够执行不区分大小写的搜索。
  • 我们的 RE 的长度不应超过 256 字节。

3.8. 目录结构

大多数主要的 Linux 发行版都符合文件系统层次标准 (FHS)。FHS 定义了一个可配置的树状目录结构。层次结构中的第一个目录是root目录,所有其他目录、文件和特殊文件都从它分支出来。

树实用程序可以让我们更好地了解目录结构:

$ tree / -d -L 1
/
├── bin -> usr/bin
├── boot
├── dev
├── etc
├── home
├── lib64 -> usr/lib
├── mnt
├── opt
├── proc
├── root
├── run
├── sbin -> usr/bin
├── sys
├── usr
└── var

*虽然层次结构是可配置的,但我们的程序不应在根目录/dev目录下创建文件或目录。*但是,它允许在任何用户目录下创建文件和目录,例如XDG Base Directory 。此外,我们还可以使用/tmp目录来创建临时文件和目录。

3.9. 实用程序

当我们熟悉 UNIX/Linux 环境中的实用程序时,我们可以看到大多数实用程序的行为是相同的。例如,我们知道*-h*选项为几乎每个 UNIX/Linux 实用程序打印帮助文本。这种一致性归功于 POSIX 描述的约定。POSIX 为程序员定义了几个关于我们应该如何实现我们的实用程序的约定。

POSIX 建议我们在实用程序中实现以下参数语法:

utility_name [-a][-b][-c option_argument]
    [-d|-e][-f[option_argument]][operand...] <parameter name>

让我们分解一下:

  • utility_name是我们的实用程序的名称,后跟选项和参数。
  • 方括号内的项目是可选的,我们可以省略它们。
  • -a和*-b*是启用或禁用程序功能的标志。
  • -c选项要求参数之间有一个空白字符
  • 由管道分隔的*-d-e*选项指定这两个选项是互斥的。
  • -f选项指定选项和选项参数应该放在一起,中间没有空白字符,并且不带参数的选项不应将下一个参数视为选项参数。
  • 操作数可以是实用程序处理的任何内容,例如文本文件。
  • 操作数后面的省略号 (…)表示我们可以向实用程序输入零个或多个操作数。
  • 尖括号内的项目需要用实际值代替。

此外,我们可以省略实用程序所需选项的括号。对于具有很多选项的复杂实用程序,我们可以将选项分组:

utility_name [-axyDnPo][-l arg][operand]

除了实用程序语法之外,POSIX 鼓励我们在实现实用程序时使用一组准则。

4. 操作系统和 POSIX 合规性

4.1.Linux

创建一个完全符合 POSIX 的基于 Linux 的操作系统当然是可能的。EulerOS 就是一个很好的例子。然而,大多数现代程序,尤其是闭源软件,部分或根本不符合标准

例如,bash shell 曾经完全符合 POSIX。然而,最新版本的bash默认不符合 POSIX 标准。因此,可以说大多数 Linux 发行版都部分兼容 POSIX。

4.3. Darwin

Darwin 是Apple 操作系统 的核心集,例如 macOS 和 iOS。它部分符合 POSIX。但是,macOS 的最新版本完全符合 POSIX 标准

4.4. Windows

Microsoft Windows 根本不符合标准,因为它的整体设计与类 UNIX 操作系统完全不同。但是,我们可以通过使用**WSL 兼容层或Cygwin 来设置符合 POSIX 的环境**。

4.5. 其他

一些专有操作系统已通过 POSIX 认证: