Sign in Join
Wiki copytemporary

Command line parameters and environment variables: what changed

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

OldNewLine
11On 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.
22
33## Overview
44
55Although 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.
66
77### Terminology
88
99Option
1010Options are yes/no flags. They usually assume the form `‑‑dryrun`/`‑‑no‑dryrun` (dryrun enabled or disabled respectively). Options are also called “switches”.
1111
1212Parameter
1313Parameters are key-value-tuples. On the command line they look like: `‑‑processors 4`.
1414
1515Argument
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.
16+Arguments are simple words. On the command line they are usually separated by spaces (confer the IFS 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.
1717
1818Environment variable
1919Environment variables refer to a labeled piece of storage in the environment. They are name-value-pairs.
2020
2121Note, 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.
2222
2323### Basics
2424
2525Since 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.
2626
2727The 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.
2828
2929## Command line parameters
3030
3131### The basics
3232
3333A 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.
3434
3535``` pascal
3636program listArguments(input, output, stdErr);
3737{$mode objFPC}
3838var
3939 i: integer;
4040begin
4141 writeLn({$ifDef Darwin}
4242 // on Mac OS X return value depends on invocation method
4343 'This program was invoked via: ',
4444 {$else}
4545 // Turbo Pascal-compliant paramStr(0) returns location
4646 'This program is/was stored at: ',
4747 {$endIf}
4848 paramStr(0));
4949
5050 for i := 1 to paramCount() do
5151 begin
5252 writeLn(i:2, '. argument: ', paramStr(i));
5353 end;
5454end.
5555```
5656
5757Running this program (on a non-Mac OS Ⅹ platform) may look like this:
5858
5959```text
6060$ ./listArguments foo bar able
6161This program is/was stored at: /tmp/listArguments
6262 1. argument: foo
6363 2. argument: bar
6464 3. argument: able
6565```
6666
6767The [[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.
6868
6969The 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.
7070
7171> **Note:** Since `paramStr(0)` relies on OS functionality, it is not suitable for [[Multiplatform Programming Guide|cross-platform programs]].
7272
7373> **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.
7474
7575The [`getOpts` unit](https://www.freepascal.org/docs-html/rtl/getopts/index.html) provides a few other routines for program invocation following a certain style.
7676
7777### User friendly
7878
7979A 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`.
8080
8181Every [[LCL]] application uses this automatically. The Application object is a TCustomApplication.
8282
8383If 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.
8484
8585#### Check for a parameter
8686
8787With 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:
8888
8989```delphi
9090if hasOption('h', 'help') then
9191begin
9292 writeHelp;
9393 halt;
9494end;
9595```
9696
9797> **Note:** In an LCL form you must prepend `application.` in front of `hasOption`.
9898
9999For example:
100100
101101```delphi
102102if application.hasOption('h', 'help') then
103103begin
104104 writeHelp;
105105 halt;
106106end;
107107```
108108
109109If you only want to support the short option, use:
110110
111111```delphi
112112if hasOption('h', '') then
113113```
114114
115115If you only want to support the long option, use:
116116
117117```delphi
118118if hasOption('help') then
119119```
120120
121121#### Read the parameter value
122122
123123Each parameter can be given a value. For example:
124124
125125``` bash
126126$ project1 -f filename
127127```
128128
129129or in the long form:
130130
131131``` bash
132132$ project1 --file=filename
133133```
134134
135135In order to retrieve `filename` use:
136136
137137```delphi
138138writeLn('f=', getOptionValue('f', 'file'));
139139```
140140
141141Note: 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.
142142
143143#### Checking parameters for validity
144144
145145Command 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:
146146
147147You 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.
148148
149149Examples:
150150
151151```delphi
152152errorMsg := checkOptions('hf:', 'help file:');
153153```
154154
155155This 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.
156156
157157A Parameter Example:
158158
159159``` pascal
160160procedure TMainForm.FormShow(Sender: TObject);
161161var
162162 I: Integer;
163163 Params : TStringList
164164 LongOpts : array [1..2] of string = ('debug-sync', 'config-dir:');
165165begin
166166 Params := TStringList.Create;
167167 try
168168 Application.GetNonOptions('hgo:', LongOpts, Params);
169169 for I := 0 to Params.Count -1 do
170170 debugln('Extra Param ' + inttostr(I) + ' is ' + Params[I]); }
171171 finally
172172 FreeAndNil(Params);
173173 end;
174174end;
175175```
176176
177177This 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.
178178
179179Note that Application.GetNonOptions() takes the long options as an array but Application.CheckOptions takes the same data but as a string. Bit sad!
180180
181181## Environment variables
182182
183183The [[sysutils|sysUtils unit]] defines three basic functions in order to retrieve environment variables.
184184
185185- [`getEnvironmentVariableCount`](https://www.freepascal.org/docs-html/rtl/sysutils/getenvironmentvariablecount.html) returns the total number of environment variables
186186- [`getEnvironmentString`](https://www.freepascal.org/docs-html/rtl/sysutils/getenvironmentstring.html) returns an environment variable by its index
187187- [`getEnvironmentVariable`](https://www.freepascal.org/docs-html/rtl/sysutils/getenvironmentvariable.html) returns an environment variable by its key
188188
189189Example:
190190
191191``` pascal
192192program environmentVariablesList(input, output, stdErr);
193193uses
194194 sysUtils;
195195var
196196 i: integer;
197197begin
198198 for i := 0 to getEnvironmentVariableCount() - 1 do
199199 begin
200200 writeLn(getEnvironmentString(i));
201201 end;
202202end.
203203```
204204
205205It 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 ('=')]].
206206
207207```delphi
208208program environmentVariablesSorted(input, output, stdErr);
209209{$mode objFPC}
210210uses
211211 classes, sysUtils;
212212var
213213 i: integer;
214214 environmentVariables: tStringList;
215215begin
216216 environmentVariables := tStringList.create();
217217
218218 try
219219 // load all variables to string list
220220 for i := 0 to getEnvironmentVariableCount() - 1 do
221221 begin
222222 environmentVariables.append(getEnvironmentString(i));
223223 end;
224224
225225 environmentVariables.sort;
226226 for i := 0 to environmentVariables.count - 1 do
227227 begin
228228 writeLn(environmentVariables.names[i]:20,
229229 ' = ',
230230 environmentVariables.valueFromIndex[i]);
231231 end;
232232 finally
233233 environmentVariables.free;
234234 end;
235235end.
236236```
237237
238238There 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:
239239
240240```delphi
241241var
242242 environmentVariables: tStringList;
243243begin
244244 environmentVariables := tStringList.create();
245245 try
246246 application.getEnvironmentList(environmentVariables);
247247 …
248248 finally
249249 environmentVariables.free;
250250 end;
251251end;
252252```
253253
254254---
255255*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).*
256256Category: Code

Back to history