Sign in Join
Wiki copytemporary

Command line parameters and environment variables/zh CN

English · Español · Français · Suomi · Русский · 中文(中国)

在大多数(交互式)操作系统中,可以通过命令行界面(CLI)启动程序,并允许向程序提供附带的数据。system单元(以及objPas)单元提供了一些基本的函数,用于访问这些通过命令行给出的数据。

概述

尽管这里介绍的是“命令行”参数和环境变量,但使用传给程序的数据,以及这里提及的例程和术语,都不需要实际用到命令行界面(CLI)。只是命令行界面更为直观,因此以下内容主要考虑 shell 用户的体验。

术语

选项(Option)

选项就是“是/否”。通常假定为如下形式

‑‑dryrun/‑‑no‑dryrun (分别为启用和禁用 dryrun 选项)。 选项也被称为“开关”。

参数(Parameter)

参数是键值元组。在命令行中的形式如下:

‑‑processors 4。

实参(Argument)

实参就是一些简单的单词。在命令行中通常以空格分隔(某些 shell 中可由 IFS 变量定义)。从狭义上讲, 实参 指既非选项也不属于参数的所有单词。而从广义上讲,实参是指命令行中未以任何方式解释的所有单词。

环境变量(Environment variable)

环境变量是指运行环境中打了标签的一块存储空间,都是“名称/值”对。

请注意,命令行界面操作系统向程序传递的参数会先进行处理:比如转义后的换行符、文件重定向(管道或重定向文件)、对环境变量的赋值,都不会传给程序。

底层函数

“选项”和“参数”的概念抽象程度已经较高,且存在不同的风格(如短选项和长选项),而 system 单元的目标是提供较为 底层 的工作方式,因此只把全部命令行参数视为从零开始的枚举类型,未做任何解释处理。

函数 paramStr 用于返回第 n 个命令行参数。 ParamStr(0) 尝试返回可执行程序文件名,以及完整路径。

命令行参数

基本用法

Pascal 程序可以将 paramStr 函数 和 paramCount 结合起来,以便访问命令行参数。

ParamCount 将返回给出的参数个数。

pascal
program listArguments(input, output, stdErr);
    {$mode objFPC}
    var
        i: integer;
    begin
        writeLn({$ifDef Darwin}
                // Mac OS X 中的返回值依赖于调用方法
                'This program was invoked via: ',
            {$else}
                // 兼容 Turbo Pascal 的 paramStr(0) 返回程序所在位置
                'This program is/was stored at: ',
            {$endIf}
            paramStr(0));
        
        for i := 1 to paramCount() do
        begin
            writeLn(i:2, '. argument: ', paramStr(i));
        end;
    end.

在非 Mac OS X 系统中,上述程序的运行结果可能如下:

pascal
$ ./listArguments foo bar able
    This program is/was stored at: /tmp/listArguments
     1. argument: foo
     2. argument: bar
     3. argument: able

RTL 的 system 单元提供了一个 paramStr,返回的是shortString 类型的字符串。shortString 类型的实现方式限制了其长度在255个字符以内。 但是用户可能会给出长度超限的命令行参数。 为了访问全部命令行参数,objPas 单元 重新定义了 paramStr,返回类型换成了 ansiString,这样长度就不受限了。在 {$mode objFPC}(第2行)和 {$mode Delphi} 编译模式下,会自动包含 objPas 单元。

提供 paramStr 函数是为了与 Turbo Pascal 保持兼容。在 Turbo Pascal 中,paramStr(0) 返回程序的所在位置。但这需要操作系统的支持。尤其值得注意的是,在 Mac OS X 系统中,paramStr(0) 的返回值取决于调用方法,即应用程序的启动方式。

https://upload.wikimedia.org/wikipedia/commons/d/d8/Nuvola_apps_ktip.png Note: 由于 paramStr(0) 依赖于操作系统的支持,所以并不适用于 跨平台应用。

https://upload.wikimedia.org/wikipedia/commons/d/d8/Nuvola_apps_ktip.png Note: 在类 Unix 系统中,只用字符串不可能确定文件的位置。可能有多个硬链接指向同一个i节点,文件可能已删除,文件路径可能已有部分改动,以及其他细节问题。

因此,在类 Unix 系统中 paramStr(0) 无效。

getOpts 单元提供了其他一些函数,在以特定格式调用程序时可用于解析命令行参数。

用户友好性

设计良好的程序在收到错误参数时应能给出帮助信息,并且应该遵循一种通用的参数传递方式。 FPC 的 unit custApp 单元提供了一个 TCustomApplication 类,可用于轻松检查和读取命令行参数。当然,用 paramStr 和 paramCount 直接访问也没问题。

LCL 应用程序都会自动使用 TCustomApplication。Application 对象就是 TCustomApplication 的实例。

若要编写非 LCL 程序,那么先在 Lazarus 中新建“控制台应用程序”类型的项目。这会创建一个包含某些实用功能的 project1.lpr,这些功能几乎所有程序都需要用到。接下来,请定位到 doRun 方法。

检测某个参数

TCustomApplication 可以通过名称访问命令行参数。 比如用户给出通用的求助参数 -h 时,程序应该打印出一条帮助文字。 -h 是个短选项。 长选项则为 --help 。 若要测试用户在调用程序时是否带有 -h 或 --help 参数,可以使用如下代码:

pascal
if hasOption('h', 'help') then
    begin
        writeHelp;
        halt;
    end;

https://upload.wikimedia.org/wikipedia/commons/d/d8/Nuvola_apps_ktip.png Note: 在 LCL 窗体中,必须在 hasOption 前面加上 application.。

例如:

pascal
if application.hasOption('h', 'help') then
    begin
        writeHelp;
        halt;
    end;

如果只支持短选项,请用以下代码:

pascal
if hasOption('h', '') then

若只支持长选项,则用:

pascal
if hasOption('help') then

读取参数值

每个命令行参数可以给定一个值。 例如:

pascal
$ project1 -f filename

或者长格式:

pascal
$ project1 --file=filename

读取 filename :

pascal
writeLn('f=', getOptionValue('f', 'file'));

注意:如果报错“Option at position 1 needs an argument : f.”,则是在调用

pascal
[checkOptions](<https://www.freepascal.org/docs-html/fcl/custapp/tcustomapplication.checkoptions.html>) 时忘记加入该选项了。

校验参数

命令行参数就是一条内容随意的文本,因此用户输入很容易出错。 因此,必须对命令行参数作语法检查。用 CheckOptions 方法即可完成检查。

可定义允许哪些参数及哪些参数需要有值,在发生语法错误时可获取错误消息和出错的选项,以便打印出帮助信息和错误细节。

示例:

pascal
errorMsg := checkOptions('hf:', 'help file:');

上述代码允许传递短选项 ‑f value 和 ‑h, 还允许 ‑‑help 或 ‑‑file=filename。 但不允许 ‑‑help 带有值,也不允许 ‑‑file 没有值。

参数示例:

pascal
procedure TMainForm.FormShow(Sender: TObject);
    var
        I: Integer;
        Params : TStringList
        LongOpts : array [1..2] of string = ('debug-sync', 'config-dir:');
    begin
        Params := TStringList.Create;
        try
            Application.GetNonOptions('hgo:', LongOpts, Params);
            for I := 0 to Params.Count -1 do
                debugln('Extra Param ' + inttostr(I) + ' is ' + Params[I]);  }
        finally
            FreeAndNil(Params);
        end;
    end;

以上例程会查找参数,且不会和命令行开关或选项混淆。 应用程序还接受 --debug-sync 和 --config-dir=somedir 开关,只是没有打印出来。

请注意,Application.GetNonOptions() 方法以数组类型的长选项为参数,而 Application.CheckOptions 方法的参数数据相同却只认字符串。 有点遗憾!

环境变量

sysUtils 单元定义了3个读取环境变量的基本函数。

示例:

pascal
program environmentVariablesList(input, output, stdErr);
    uses
        sysUtils;
    var
        i: integer;
    begin
        for i := 0 to getEnvironmentVariableCount() - 1 do
        begin
            writeLn(getEnvironmentString(i));
        end;
    end.

另外还有一种可能的方式,就是将所有环境变量载入 tStringList对象,以便访问键值对。 字符串列表会自动处理分隔符,默认为等号 ('=')。

pascal
program environmentVariablesSorted(input, output, stdErr);
    {$mode objFPC}
    uses
        classes, sysUtils;
    var
        i: integer;
        environmentVariables: tStringList;
    begin
        environmentVariables := tStringList.create();
        
        try
            // load all variables to string list
            for i := 0 to getEnvironmentVariableCount() - 1 do
            begin
                environmentVariables.append(getEnvironmentString(i));
            end;
            
            environmentVariables.sort;
            for i := 0 to environmentVariables.count - 1 do
            begin
                writeLn(environmentVariables.names[i]:20,
                    ' = ',
                    environmentVariables.valueFromIndex[i]);
            end;
        finally
            environmentVariables.free;
        end;
    end.

还可以采用 tCustomApplication 的 方法,可一次性将全部环境变量读取为一个tStringList。大致如下所示:

pascal
var
        environmentVariables: tStringList;
    begin
        environmentVariables := tStringList.create();
        try
            application.getEnvironmentList(environmentVariables);
            ???
        finally 
            environmentVariables.free;
        end;
    end;

*[IFS]: internal field separator


From the Free Pascal wiki, page "Command line parameters and environment variables/zh CN", as the Internet Archive kept it on 2025-01-13, last changed on 2024-12-09. Copyright stays with the author who wrote it, according to the old wiki's Licensing page. If you have concerns about this material, message the admin.

Revision 3, last changed by WikiArchive .

Talk about this page

Nobody has opened a bench for this page yet. Sign in to open one.