Sign in Join
Wiki copytemporary

Command line parameters and environment variables: what changed

Revision 0 to 1. Removed lines have a minus sign; added lines have a plus sign.

Title: Command line parameters and environment variables

OldNewLine
1+On most (interactive) operating systems [[Program|programs]] can be started via a [[Command-line interface|command line interface]] (CLI) that allows supplying the program with additional data. The [[System unit|system]] (and [[Object Pascal|objPas]]) units provide basic [[Function|functions]] in order to access command-line supplied data.
2+
3+## Overview
4+
5+Although this page speaks of *command-line* parameters and environment variables, an actual command line interface (CLI) is not a requirement to use such data, nor to use the routines and terminology described here. However, since a CLI is more tangible the following instructions mainly to refer to a shell’s user experience.
6+
7+### Terminology
8+
9+Option
10+Options are yes/no flags. They usually assume the form `‑‑dryrun`/`‑‑no‑dryrun` (dryrun enabled or disabled respectively). Options are also called “switches”.
11+
12+Parameter
13+Parameters are key-value-tuples. On the command line they look like: `‑‑processors 4`.
14+
15+Argument
16+Arguments are simple words. On the command line they are usually separated by spaces (confer the <abbr title="internal field separator">IFS</abbr> variable in some shells). In a narrow sense *arguments* are all supplied words that are neither options or (part of) parameters. In general, though, arguments are all words on the command line not being interpreted in any way.
17+
18+Environment variable
19+Environment variables refer to a labeled piece of storage in the environment. They are name-value-pairs.
20+
21+Note, the CLI/OS provides the program only with arguments it is supposed to get: For example, escaped newline characters, file redirection (pipes or to a file), and assignment of environment variables will not be forwarded to the program.
22+
23+### Basics
24+
25+Since the notion of “option” and “parameters” are already kind of high-level, different styles exist (short options vs. long options), and the system unit aims to provide the *basic* means to work with, all command line arguments are simply enumerated starting from zero. No interpretation is done.
26+
27+The function [`paramStr`](https://www.freepascal.org/docs-html/rtl/system/paramstr.html) returns the n-th argument on the command line. `ParamStr(0)` tries returning the name, and possibly full path to the executable program file.
28+
29+## Command line parameters
30+
31+### The basics
32+
33+A Pascal program can a access command line arguments by using the `paramStr` [[Function|function]] in conjunction with [`paramCount`](https://www.freepascal.org/docs-html/rtl/system/paramcount.html). `ParamCount` returns the number of supplied arguments.
34+
35+``` pascal
36+program listArguments(input, output, stdErr);
37+{$mode objFPC}
38+var
39+ i: integer;
40+begin
41+ writeLn({$ifDef Darwin}
42+ // on Mac OS X return value depends on invocation method
43+ 'This program was invoked via: ',
44+ {$else}
45+ // Turbo Pascal-compliant paramStr(0) returns location
46+ 'This program is/was stored at: ',
47+ {$endIf}
48+ paramStr(0));
49+
50+ for i := 1 to paramCount() do
51+ begin
52+ writeLn(i:2, '. argument: ', paramStr(i));
53+ end;
54+end.
55+```
56+
57+Running this program (on a non-Mac OS Ⅹ platform) may look like this:
58+
59+```text
60+$ ./listArguments foo bar able
61+This program is/was stored at: /tmp/listArguments
62+ 1. argument: foo
63+ 2. argument: bar
64+ 3. argument: able
65+```
66+
67+The [[RTL]]’s system unit provides a `paramStr` version that returns [[Shortstring|shortStrings]]. Due to their implementation `shortString`s are capped at 255 characters. However the user may supply longer command line arguments. To access them the [`objPas` unit](https://www.freepascal.org/docs-html/rtl/objpas/index.html) redefines `paramStr` that returns [[Ansistring|ansiStrings]] instead which do not have this length limitation. The `objPas` unit is automatically included in the [[Mode ObjFPC|{$mode objFPC}]] (line 2) and [[Mode Delphi|{$mode Delphi}]] compiler modes.
68+
69+The distributed `paramStr` function tries to be [[Turbo Pascal]]-compliant. In TP `paramStr(0)` returns the location of the program. However, the operating system needs to support that. Most notably, on Mac OS Ⅹ the value of `paramStr(0)` depends on the invocation method, how the application is being started.
70+
71+> **Note:** Since `paramStr(0)` relies on OS functionality, it is not suitable for [[Multiplatform Programming Guide|cross-platform programs]].
72+
73+> **Note:** On Unixoid platforms it is impossible to accurately define the location of a file merely by a string. There could be multiple hard-links pointing to the same inode, the file could have already been deleted, parts of the file path might have changed, beside other details. For these reasons, `paramStr(0)` is useless on Unixoid platforms.
74+
75+The [`getOpts` unit](https://www.freepascal.org/docs-html/rtl/getopts/index.html) provides a few other routines for program invocation following a certain style.
76+
77+### User friendly
78+
79+A good program should give a help message when invoked with the wrong parameters and it should follow a common way of giving parameters. The [unit `custApp`](https://www.freepascal.org/docs-html/fcl/custapp/index.html) that comes with FPC provides the [`TCustomApplication` class](https://www.freepascal.org/docs-html/fcl/custapp/tcustomapplication.html), which provides functions to easily check and read parameters. Of course you can still access the parameters directly via `paramStr` and `paramCount`.
80+
81+Every [[LCL]] application uses this automatically. The Application object is a TCustomApplication.
82+
83+If you want to write a non LCL program, then create in [[Lazarus]] a new project of type “Console Application”. This will create a project1.lpr with some nice goodies, that almost all programs need. Go to the `doRun` method.
84+
85+#### Check for a parameter
86+
87+With TCustomApplication you can access parameters by name. For example your program should print a help text when the user gave the common help parameter *-h*. The *-h* is a short option. The long form is the *--help*. To test whether the user called the program with *-h* or *--help* you can use:
88+
89+```delphi
90+if hasOption('h', 'help') then
91+begin
92+ writeHelp;
93+ halt;
94+end;
95+```
96+
97+> **Note:** In an LCL form you must prepend `application.` in front of `hasOption`.
98+
99+For example:
100+
101+```delphi
102+if application.hasOption('h', 'help') then
103+begin
104+ writeHelp;
105+ halt;
106+end;
107+```
108+
109+If you only want to support the short option, use:
110+
111+```delphi
112+if hasOption('h', '') then
113+```
114+
115+If you only want to support the long option, use:
116+
117+```delphi
118+if hasOption('help') then
119+```
120+
121+#### Read the parameter value
122+
123+Each parameter can be given a value. For example:
124+
125+``` bash
126+$ project1 -f filename
127+```
128+
129+or in the long form:
130+
131+``` bash
132+$ project1 --file=filename
133+```
134+
135+In order to retrieve `filename` use:
136+
137+```delphi
138+writeLn('f=', getOptionValue('f', 'file'));
139+```
140+
141+Note: if you get the error message “`Option at position 1 needs an argument : f.`” then you forgot to add the option in the [`checkOptions`](https://www.freepascal.org/docs-html/fcl/custapp/tcustomapplication.checkoptions.html) call.
142+
143+#### Checking parameters for validity
144+
145+Command line parameters are free text, so the user can easily type errors. Checking the syntax of the parameters is therefore mandatory. You can use the [[doc:fcl/custapp/tcustomapplication.checkoptions.html|CheckOptions]] method for this:
146+
147+You can define, what parameters are allowed, which ones ones need a parameter and in case of a syntax error you can get an error message plus the options that were wrong to print helpful and detailed errors.
148+
149+Examples:
150+
151+```delphi
152+errorMsg := checkOptions('hf:', 'help file:');
153+```
154+
155+This allows passing short options `‑f value` and `‑h`. It allows passing long options `‑‑help` or `‑‑file=filename`. It does not allow `‑‑help` with a value, nor `‑‑file` without a value.
156+
157+A Parameter Example:
158+
159+``` pascal
160+procedure TMainForm.FormShow(Sender: TObject);
161+var
162+ I: Integer;
163+ Params : TStringList
164+ LongOpts : array [1..2] of string = ('debug-sync', 'config-dir:');
165+begin
166+ Params := TStringList.Create;
167+ try
168+ Application.GetNonOptions('hgo:', LongOpts, Params);
169+ for I := 0 to Params.Count -1 do
170+ debugln('Extra Param ' + inttostr(I) + ' is ' + Params[I]); }
171+ finally
172+ FreeAndNil(Params);
173+ end;
174+end;
175+```
176+
177+This example finds parameters and does not mix them with command line switches or options. In this example, the app also accepts the switches --debug-sync and --config-dir=somedir but they are not reported here.
178+
179+Note that Application.GetNonOptions() takes the long options as an array but Application.CheckOptions takes the same data but as a string. Bit sad!
180+
181+## Environment variables
182+
183+The [[sysutils|sysUtils unit]] defines three basic functions in order to retrieve environment variables.
184+
185+- [`getEnvironmentVariableCount`](https://www.freepascal.org/docs-html/rtl/sysutils/getenvironmentvariablecount.html) returns the total number of environment variables
186+- [`getEnvironmentString`](https://www.freepascal.org/docs-html/rtl/sysutils/getenvironmentstring.html) returns an environment variable by its index
187+- [`getEnvironmentVariable`](https://www.freepascal.org/docs-html/rtl/sysutils/getenvironmentvariable.html) returns an environment variable by its key
188+
189+Example:
190+
191+``` pascal
192+program environmentVariablesList(input, output, stdErr);
193+uses
194+ sysUtils;
195+var
196+ i: integer;
197+begin
198+ for i := 0 to getEnvironmentVariableCount() - 1 do
199+ begin
200+ writeLn(getEnvironmentString(i));
201+ end;
202+end.
203+```
204+
205+It is also possible to load all environment variables to a [`tStringList` object](https://www.freepascal.org/docs-html/rtl/classes/tstringlist.html) and access to name-value pair easily. String lists automatically take care of the separator character which is by defaut is an [[=|equal sign ('=')]].
206+
207+```delphi
208+program environmentVariablesSorted(input, output, stdErr);
209+{$mode objFPC}
210+uses
211+ classes, sysUtils;
212+var
213+ i: integer;
214+ environmentVariables: tStringList;
215+begin
216+ environmentVariables := tStringList.create();
217+
218+ try
219+ // load all variables to string list
220+ for i := 0 to getEnvironmentVariableCount() - 1 do
221+ begin
222+ environmentVariables.append(getEnvironmentString(i));
223+ end;
224+
225+ environmentVariables.sort;
226+ for i := 0 to environmentVariables.count - 1 do
227+ begin
228+ writeLn(environmentVariables.names[i]:20,
229+ ' = ',
230+ environmentVariables.valueFromIndex[i]);
231+ end;
232+ finally
233+ environmentVariables.free;
234+ end;
235+end.
236+```
237+
238+There is also a `tCustomApplication` [[Method|method]] available to get all environment variables as a [[TStringList|tStringList]] at once. Then the pattern may look like this:
239+
240+```delphi
241+var
242+ environmentVariables: tStringList;
243+begin
244+ environmentVariables := tStringList.create();
245+ try
246+ application.getEnvironmentList(environmentVariables);
247+ …
248+ finally
249+ environmentVariables.free;
250+ end;
251+end;
252+```
253+
254+---
255+*From the Free Pascal wiki, page "Command line parameters and environment variables", as it stood on 2022-05-16 after a change by Kai Burghardt, out of the wiki's dump of 2024-05-26. 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](/wiki-contact).*
256+Category: Code

Back to history