How to flexibly handle parameters in our shell scripts

botond published Jan. 2019, 09, 11:15 p.m. time

Content

 

Introductory

When programming, it is important that when we write a program that performs a certain task, our code should be prepared for several possibilities, variations and, if possible, parameterized - with which we can make its operation fine-tuned. This is no different for shell scripts. In today’s example, we’ll look at how we can flexibly handle the parameters we get in our scripts, making it easier to create programs that are easier for others to use.

 

 

Structure of the program

create

Create any file, for example:

touch parameterek_rugalmas_feldolgozasa

Then let it run:

chmod +x parameterek_rugalmas_feldolgozasa

Then the edits can come:

nano parameterek_rugalmas_feldolgozasa

And if there is content, sometimes the program will try. in another terminal:

./ nano parameterek_rugalmas_feldolgozasa

We can also start.

The basics

First, set up the base of our program, where we place the associative array for our switches and some other default settings.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#!/bin/bash
# ------------------------------------------------------------------------------
# Linuxportál példaprogram: Paraméterek rugalmas feldolgozása
# ------------------------------------------------------------------------------
 
 
# ----------------------------------------------------------
# Kapcsolók/paraméterek alapértelmezett értékei
# ----------------------------------------------------------
declare -A PARAMS
PARAMS=(
    [DEBUG]=""                                              # Debug mód
    [HELP]=""                                               # súgó megjelenítése
    [VERSION]=""                                            # Verzió információk
    [EGYEB1]=""                                             # Egyéb paraméter #1
    [EGYEB2]=""                                             # Egyéb paraméter #2
    [EGYEB3]=""                                             # Egyéb paraméter #3
    [EGYEB4]=""                                             # Egyéb paraméter #4
)
 
 
# ----------------------------------------------------------
# További beállítások
# ----------------------------------------------------------
tabs 4                                                      # Kimenetben megjelenített tab-ok karakter mérete.
shopt -s nocasematch                                        # Kis- és nagybetűk figyelmen kívül hagyása a case szerkezetekben
green=$(tput setaf 2)                                       # Zöld kiemelőszín
red=$(tput setaf 1)                                         # Piros kiemelőszín
cyan=$(tput setaf 6)                                        # Cián kiemelőszín
reset=$(tput sgr0)                                          # Színek alapállapotba állítása
escape_value="***"                                          # "Menekülési érték", ha nincs megadva valamelyik kötelező érték
 
VERSION="1.0"                                               # Program verziója

Here we first declare our associative array named PARAMS and then create the storage elements for the parameters used in our program, which are populated with default values ​​(in this case with empty strings). These array elements will store the switches received during the program run, which can then be conveniently accessed. THE Bash it does not require you to pre-declare the elements in the arrays, but you should do so just to open the file later to see immediately what variables / tags you have used in your program. This makes it easier to see our code afterwards, if we need to change it in half a year.

You don't have to use an associative array for this purpose, it would be enough to store the received arguments in plain variables, but this way it is more uniform, we don't mix them with other variables in the program (especially if we have to source another script into this file later) , and an array can be traversed more easily with a single loop if necessary than searching for values ​​in "scattered" variables. THE of arrays in this description you can find more information.

Then we place a few values ​​in the Additional settings rows:

  • tabs 4: We set Bash to always display tabs 4 characters wide in the output of our program.
  • shopt -s nocasematch: On this SHOP command to set Bash not to case-sensitive in the case branch evaluations while the program is running. This significantly reduces the number of possible errors, because it does not matter whether the parameters are entered in lowercase or uppercase.
  • green, red, cyan, reset: Color settings a tput using the command. These allow us to highlight our outputs in different colors. About this a How to Use Colors in the Terminal For detailed information, see.
  • escape_value: In this variable, we need to set our own "escape value" - which we certainly won't get during normal use of the program. This is intended to be below Parameter pre-processing by replacing it partially with empty values ​​in the sections below, we can distinguish between the total absence of the switch and the absence of values ​​so that we can generate an error if the required values ​​are not met.
  • VERSION: Here, we only give a version number to our program, which we can then query with the appropriate switches.

Creating a library

We also need snippets of code that we can reuse while our program is running. Examples include displaying the title, displaying help, displaying the version, and so on. We place these parts in functions so that we can call them from anywhere in our program. To do this, we create a library section where the functions are listed. This makes the source code easier to maintain. So we continue our code with the functions:

36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
# ----------------------------------------------------------
# Függvénytár
# ----------------------------------------------------------
 
# Cím kirakó függvény
function print_title() {
    echo "Linuxportál példaprogram - Paraméterek rugalmas feldolgozása"
}
 
# Verzió kirakó függvény
function print_version() {
    echo "Verzió: $VERSION"
}
 
# Súgó kirakó függvény
function print_help() {
cat << EOF
Használat: 
$(basename $0) [kapcsoló] [érték] ... vagy
$(basename $0) [kapcsoló]=[érték] ...
Kapcsolók:
  -h,       --help          Súgó megjelenítése
  -d,       --debug         Debug mód. Ha meg van adva, akkor kiírja a futás során a használt összes kapcsoló változót.
  -v,       --version       Verzió lekérdezése
  -e1,      --egyeb1        Egyéb 1 funkció futtatása
  -e2=x,    --egyeb2=x      Egyéb 2 tároló paraméter demonstrálása
  -e3,      --egyeb3        Egyéb 3 logikai tároló paraméter demonstrálása
  -e4=x,    --egyeb4=x      Egyéb 4 tároló paraméter demonstrálása
EOF
}
 
# "Kis" súgó kirakó függvény
function print_help2() {
    echo "Súgó megjelenítése: $(basename $0) -h vagy --help"
}

So here we have four functions. The first is obvious, these are the title and version of the program. And the print_help () function provides help. Here, due to the multiple serial and tabular outputs, we present the formatted output in a heredoc (Here-document) instead of the usual echoes. so you don't have to line up the quotation marks line by line.

The help also shows that the various functions can be accessed with two types of switches: short and long - as is the case with most Linux programs. Furthermore, the values ​​will be processed in two ways, with or without an equal sign.

It is also worth noting here that in this form we cannot apply indents on the heredoc in the function block, because then it throws an error. If we still want to tabulate the lines - to make our function look nicer - let's start with the document: "cat << - EOF". So put a hyphen between the "left beaks" and the opening / closing sequence (in this case EOF). This way we can already apply indents to the lines of the document. However, in this case, the output does not take into account the tabs at the beginning of the lines, only the content is calculated from the first character (which can be a space). So it's more cautious to format the output. This will be discussed in more detail in another description.

And finally, our print_help2 () function serves only one practical purpose: if we find an error somewhere while processing the parameters - for example, they were entered incorrectly by the user - we will expose this little help after the error message. This indicates how you can view the complete help. This way, the error message does not escape attention - as opposed to the main help, which can be many pages long, so the user can easily lose sight of important error information.

 

 

Program start, pre-processing of parameters

All the important things have been completed so far, the start of the program may come. This is really just a symbolic part, here we write to the output first, so here's something really happening first:

73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
# ----------------------------------------------------------
# Program indulás
# ----------------------------------------------------------
print_title                                                 # kiírjuk a címet. Ezt minden esetben kitesszük
 
 
# ----------------------------------------------------------
# Paraméterek előfeldolgozása
# ----------------------------------------------------------
 
# Nulla paraméter vizsgálata
if [[ $# -eq 0 ]] ; then                                    # Ha nem kapott paramétert a program, akkor 
    echo "${red}Hiba: Nincsenek paraméterek!${reset}" >&2   # Hibakimenetre írunk.
    print_help2                                             # Kis súgó kirakása
    exit 1                                                  # és kilépés 1-es hibakóddal
fi

In the Parameter Preprocessing section, we begin to examine the arguments. First, let's see if the program has received any switches or parameters. If you do not receive one, it prints the error message with a red highlight, which is directed to the error output (stderr), then exposes a single line of help and exits with an 1 error code. This way the program will not run.

Error outputs and exit codes are important because, for example, if you run a program from another script, your program can communicate with the program that called it with the exit code. For example, if you exit here with error code 1, then $? the result of this can be retrieved in a variable, which can then be used in further branches, error handling, etc. So if we follow these, we can use our programs nested at any time later, knowing that the error codes will be returned to the running parts. This allows us to use our current source code even as part of a larger automation system.

So if we run the program so far without switches, we get the following output:

Example Program - Flexible Parameter Processing - Run without Parameters

We now continue our program with a while loop in which we preprocess the resulting parameters:

90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
REMAIN_PARAMETERS=()                                        # Maradék (nem várt) paraméterek tömbjének létrehozása
while [[ $# -gt 0 ]] ; do                                   # Ciklus indul, és megy, amíg maradt paraméter.
    parameter="$1"                                          # Soron következő első paraméter kiolvasása
    need_shift=0                                            # "shift szükséges" flag nullázása.
 
    # Egyenlőség jeles paraméterek kezelése
    if [[ $parameter = *"="* ]]; then                       # Ha a soron következő első paraméter tartalmaz "=" jelet, akkor
        key=${parameter%%=*}                                # a kulcs lesz az első egyenlőség jel előtti rész,
        value=${parameter#*=}                               # az érték pedig az első egyenlőség jel utáni rész.
    else                                                    # Ha a paraméterben nem volt egyenlőség jel, akkor
        key=$parameter                                      # a kulcs lesz maga a kapott paraméter
        value=$2                                            # és az utána lévő paraméter pedig lesz az esetleges érték.
        need_shift=1                                        # Itt jelezzük a lenti részeknek, hogy kell-e a plusz paraméter forgatás.
    fi
 
    # Kapcsolók elágazása
    case $key in                                            # case szerkezet: megvizsgáljuk a kulcsot, hogy mit tartalmaz.
        -h|--help)                                          # Súgó (logikai) kapcsoló érkezett...
            shift                                           # Shift-eljük (forgatjuk) a paramétereket
            PARAMS[HELP]=1                                  # Logikai érték beállítása az ennek fentartott tömb elemében.
        ;;
        -d|--debug)                                         # debug (logikai) kapcsoló ékezett...
            shift                                           # Shift-eljük (forgatjuk) a paramétereket
            PARAMS[DEBUG]=1                                 # Logikai érték beállítása az ennek fentartott tömb elemében.
        ;;
        -v|--version)                                       # verzió (logikai) kapcsoló érkezett...
            shift                                           # Shift-eljük (forgatjuk) a paramétereket
            PARAMS[VERSION]=1                               # Logikai érték beállítása az ennek fentartott tömb elemében.
        ;;
        -e1|--egyeb1)                                       # egyeb1 (logikai) kapcsoló érkezett...
            shift                                           # Shift-eljük (forgatjuk) a paramétereket
            PARAMS[EGYEB1]=1                                # Logikai érték beállítása az ennek fentartott tömb elemében.
        ;;
        -e2|--egyeb2)                                       # egyeb1 (értéket tároló) kapcsoló érkezett...
            shift                                           # Shift-eljük (forgatjuk) a paramétereket
            [[ "$value" == "" ]] && value=$escape_value     # Ha nem kapott értéket ez a kapcsoló, akkor beletesszük a menekülési értéket
            PARAMS[EGYEB2]=$value                           # a fentebb megállapított érték tárolása az ennek fentartott tömb elemében.
            [[ "$need_shift" == 1 ]] && shift               # Ha szükséges a paraméterek forgatása, akkor még egyszer forgatjuk.
        ;;
        -e3|--egyeb3)                                       # egyeb3 (logikai) kapcsoló érkezett...
            shift                                           # Shift-eljük (forgatjuk) a paramétereket
            PARAMS[EGYEB3]=1                                # Logikai érték beállítása az ennek fentartott tömb elemében.
        ;;
        -e4|--egyeb4)                                       # egyeb4 (értéket tároló) kapcsoló érkezett...
            shift                                           # Shift-eljük (forgatjuk) a paramétereket
            [[ "$value" == "" ]] && value=$escape_value     # Ha nem kapott értéket ez a kapcsoló, akkor beletesszük a menekülési értéket
            PARAMS[EGYEB4]=$value                           # a fentebb megállapított érték tárolása az ennek fentartott tömb elemében.
            [[ "$need_shift" == 1 ]] && shift               # Ha szükséges a paraméterek forgatása, akkor még egyszer forgatjuk.
        ;;
        *)                                                  # Ha ismeretlen paraméter jön a sorban, akkor
            shift                                           # Shift-eljük (forgatjuk) a paramétereket
            REMAIN_PARAMETERS+=("$key")                     # Felvesszük a kapott paramétert a maradék (nem várt) paraméterek tömbjébe.
        ;;
    esac                                                    # case vége
done                                                        # ciklus vége
# Idáig tehát "elfogyasztottuk" az összes paramétert a shift-ek által.
 
# Beállítjuk a megmaradt egyéb paramétereket a szabványos $1, $2, $3, stb változókba
# Így könnyebb a maradékot feldolgozni később, amennyiben szükséges.
set -- "${REMAIN_PARAMETERS[@]}"

At the beginning of this section, we create an array called REMAIN_PARAMETERS, where we collect unexpected parameters during preprocessing for possible subsequent processing.

We then start a while loop, which lasts until the program runs out of parameters. The logic of this is to first examine whether the next first parameter contains an equal sign. If it contains an equal sign, we divide the parameter in half along it; the first part will be the key and then the part after the equal sign will be the value. In this case, we also got the switch and its value in a single parameter because they were not separated by a space. In this case, you will only need to rotate the arguments once with the shift command in the case section below, as we only use one parameter. The other case is when the resulting parameter does not contain an equal sign. In this case, we either get only one logic switch, which does not need a value, but only its presence, or the parameter after it will have its own value. So here once we have to rotate the parameters, which "disappears" the key in the first round. And if the switch must also carry a value, which is why we use the next parameter as well, then in this case we have to rotate the list of parameters again, so we have to delete another parameter in the section below. Then it starts all over again until the parameters run out.

The subsequent case structure is still part of the preprocessing, as no operation is performed here yet, only the rotation of the parameters is performed and the values ​​of the switches are stored. Briefly going through the switches in the example:

  • -h vagy --help: It's a logical switch, it doesn't need value. Here we rotate the parameters with the shift command and set the logical 1 to the appropriate variable.
  • -d vagy --debug, -v vagy --version and -e1 vagy --other1A: These three switches work the same way. Shift and set the corresponding array element to 1
  • -e2 vagy --other2: This is a switch with a value, first we shift here first, then if there is no value a $ value variable, we execute the escape value set at the beginning of the program, so that we can detect a value without a value in the subsequent operations, so that we can throw an error.
    We then loaded the value of $ value into the appropriate array element - which contains either the value set above or the escape value - and then shift the parameters again if there was no equal sign, so we had to use the next parameter as a value as well.
  • -e3 vagy --other3: This is also a logical switch like the first 4.
  • -e4 vagy --other4: This is also a value switch, like -e2 or --other2, so we do the same here.
  • *: And if we get a parameter that doesn't fit any of the above, then this branch is executed, where we also rotate one of the parameters, and then put the unknown argument above into the array of unexpected parameters.

With this mechanism, we can achieve four things at once:

  • The order of the switches does not matter, since the preprocessing section went through all of them and set the appropriate values ​​(logical 1s or unique values) to the appropriate array elements.
  • You can assign a value to a parameter with or without an equal sign (separated by a space)
  • The switches can be used with their short and long names, as desired.
  • We can use more complex switches (eg interdependent or complementary switches) because we have already gone through all of them, so we can evaluate them at the same time.

In the last line of this section, we return unexpected parameters to the main program parameters. So we can use them for anything later if needed.

 

 

Running a program

After that, the program can run, which basically performs the necessary operations based on the preprocessed variables:

Debug mode

152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
# ----------------------------------------------------------
# Program futás
# ----------------------------------------------------------
 
# Debug mód. Ezt vizsgáljuk legelőször, hogy bármikor le tudjon futni
if [[ "${PARAMS[DEBUG]}" == 1 ]]; then
    echo $cyan
    echo "**********************************************"
    echo "DEBUG mód"
    echo "**********************************************"
    echo "Várt paraméterek:"
    for key in "${!PARAMS[@]}"; do echo "$key: ${PARAMS[$key]}" ; done
    echo
    echo "Nem várt paraméterek: ${REMAIN_PARAMETERS[@]}"
    echo "**********************************************"   
    echo $reset
fi

Here you can see the debug mode, which traverses the PARAMS array in a loop and prints its keys and values, which were populated with the received options in the preprocessing section, and also lists the unexpected parameters - if we use the -d vagy --debug option:

Example Program - Flexible Parameter Processing - Debug Mode

Show help

Under the following condition, we'll show you help:

171
172
173
174
175
176
# Súgó megjelenítése
if [[ "${PARAMS[HELP]}" == 1 ]]; then
    print_help
    echo
    exit 0
fi

Here, following the HELP logical value of the PARAMS array, we call our help function and exit. After that, you cannot run any other functions, whatever switches you have specified (except for the debug mode already processed above):

Example Program - Flexible Parameter Processing - Show Help

Show version

In the same way, we check the variable for the version display switch and call our version display function accordingly:

179
180
181
182
183
184
# Verziószám megjelenítése
if [[ "${PARAMS[VERSION]}" == 1 ]]; then
    print_version
    echo
    exit 0
fi

Execution of other operations

Logic switches

The "Other 1" logic switch is implemented as follows:

187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
# Egyéb 1 logikai kapcsoló kiértékelése és a hozzá tartozó művelet végrehajtása
if [[ "${PARAMS[EGYEB1]}" == 1 ]]; then                     # Itt csak logikai 1 értéket vizsgálunk
    # Saját műveletünk végrehajtása...
    echo "Egyéb 1 logikai kapcsoló érzékelve, művelet végrehajtása..."   # Ez ad valamilyen kimenetet...
    # ...
    # ...
 
    
    # Művelet utáni hiba kiértékelés
    result=$?                                               # Hibakód kiolvasása
    if (( $result == 0 )); then                             # Hiba kiértékelése: Ha nem volt hiba
        echo "${green}Az 'Egyéb 1' művelet sikeresen lefutott.${reset}"
#       exit 0                                              # Itt saját ízlés szerint kilépünk,
                                                            # ha nem szeretnénk további műveleteket végrehajtani ez után.
    else                                                    # Ha hiba lépett fel a műveletünk során, akkor
        echo "${red}Hiba történt az 'Egyéb 1' művelet során!${reset}" >&2
        exit 10                                             # Kilépünk egy magunk által meghatározott hibakóddal
    fi
    echo                                                    # Üres sor kihagyása
fi

Being a logical switch, here we only examine the presence of the switch itself, that is, the 1 value loaded in the preprocessor part in the corresponding array index. Once this is done, we run our desired operation, then evaluate its effectiveness and provide feedback accordingly:

  • After the operation has run successfully, the user is notified of the results of the operation with green text highlighting in the first branch. Here you can even use the exit command as needed, depending on whether you want the program to stop running after the operation, or rather let it continue to run. In the example, I commented this out so that we can monitor all operations at once with one run.
  • And in the incorrect section of the evaluation, we will notify the user by red highlighting a error in output, and then abort the program with a unique error code.

Finally, for the sake of clarity of the output, omit a blank line. Unfortunately, this is not addressed in most Linux commands, so everything merges. That’s why I try to use colors in as many places as possible and serve the output in a busier, more articulated, clearer way, so that working in a terminal for a longer period of time is not so exhausting to our eyes. Operating in a colorless, stimulus-poor terminal also weakens our attention sooner.

The operating principle of the "Other 3" logic switch is the same, so I will not go into detail here.

Value transfer switches

And the switch that passes the "Other 2" value is developed as follows:

209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
# Egyéb 2 kapcsoló kiértékelése és a hozzá tartozó művelet végrehajtása
if [[ "${PARAMS[EGYEB2]}" != "" ]]; then                    # Ha bármilyen érték van benne, lefut ez a rész
 
    # Kötelező érték vizsgálata. Ez a rész opcionális, amennyiben mindenképpen várunk valamilyen értéket ebben a kapcsolóban.
    if [[ "${PARAMS[EGYEB2]}" == "$escape_value" ]]; then   # Ha a változóban a menekülési érték van benne, akkor hibával leállunk.
        echo "${red}Hiba: Az 'Egyéb 2' kapcsoló érzékelve, de nem kapott értéket!${reset}" >&2
        exit 20                                             # Kilépünk egy magunk által meghatározott hibakóddal
    fi
 
    # Saját műveletünk végrehajtása...
    echo "Egyéb 2 kapcsoló érzékelve, művelet végrehajtása..."   # Ez ad valamilyen kimenetet...
    echo "A kapott érték: '${PARAMS[EGYEB2]}'"                # Kiírjuk a kapott értéket. 
    # ...
    # ...
 
    # Művelet utáni hiba kiértékelés
    result=$?                                               # Hibakód kiolvasása
    if (( $result == 0 )); then                             # Hiba kiértékelése: Ha nem volt hiba
        echo "${green}Az 'Egyéb 2' művelet sikeresen lefutott.${reset}"
#       exit 0                                              # Itt saját ízlés szerint kilépünk,
                                                            # ha nem szeretnénk további műveleteket végrehajtani ez után.
    else                                                    # Ha hiba lépett fel a műveletünk során, akkor
        echo "${red}Hiba történt az 'Egyéb 2' művelet során!${reset}" >&2
        exit 21                                             # Kilépünk egy magunk által meghatározott hibakóddal
    fi
    echo                                                    # Üres sor kihagyása
fi

The implementation of this is different from its logical switch in that in our main condition we observe cases other than the empty string. At the beginning of the program in the PARAM array, when we set the default values, the variables in the various switches were given the empty string "" value. so by default there is a corresponding element of the array but nothing in it. Therefore, when a program receives such a switch and gives it a value, that value is included. If, on the other hand, the value falls behind such a switch, the escape value is included.

So we first check if the program received this switch at all (anything other than empty) and then in line 213 we examine the value in it: if we have the escape value in it, it means that the value of this switch. in this case we generate an error, because it differs from the logic switch in that it must also receive a value: we write to the error output with a red highlight, then we interrupt the program with a unique error code.

And from there, the story is the same as for logical switches: performing your own operation, evaluating the error, and writing to the output.

The principle of operation of the switch transmitting the value "Other 4" is the same, so I will not go into detail here.

Operational examples

The following examples illustrate the behavior of the program described above:

Example Program - Flexible Parameter Processing - Switch Operation

On the first run you will see the following:

  • The order of the switches / parameters does not matter.
  • The switches can be used with their short and long names
  • You can pass values ​​to the switches with a space and an equal sign.
  • The specified value may contain an additional equals sign, it does not interfere with the operation.

On the second run, I deliberately set the "Other 4" switch to an empty value so we can see its error handling.

The following picture shows that the switches are case sensitive:

Example Program - Flexible Parameter Processing - Switch Operation - 2

 

 

Complete example program

And here's a full sample program, so if you want to try it out, here's an easy copy:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
#!/bin/bash
# ------------------------------------------------------------------------------
# Linuxportál példaprogram: Paraméterek rugalmas feldolgozása
# ------------------------------------------------------------------------------
 
 
# ----------------------------------------------------------
# Kapcsolók/paraméterek alapértelmezett értékei
# ----------------------------------------------------------
declare -A PARAMS
PARAMS=(
    [DEBUG]=""                                              # Debug mód
    [HELP]=""                                               # súgó megjelenítése
    [VERSION]=""                                            # Verzió információk
    [EGYEB1]=""                                             # Egyéb paraméter #1
    [EGYEB2]=""                                             # Egyéb paraméter #2
    [EGYEB3]=""                                             # Egyéb paraméter #3
    [EGYEB4]=""                                             # Egyéb paraméter #4
)
 
 
# ----------------------------------------------------------
# További beállítások
# ----------------------------------------------------------
tabs 4                                                      # Kimenetben megjelenített tab-ok karakter mérete.
shopt -s nocasematch                                        # Kis- és nagybetűk figyelmen kívül hagyása a case szerkezetekben
green=$(tput setaf 2)                                       # Zöld kiemelőszín
red=$(tput setaf 1)                                         # Piros kiemelőszín
cyan=$(tput setaf 6)                                        # Cián kiemelőszín
reset=$(tput sgr0)                                          # Színek alapállapotba állítása
escape_value="***"                                          # "Menekülési érték", ha nincs megadva valamelyik kötelező érték
 
VERSION="1.0"                                               # Program verziója
 
 
# ----------------------------------------------------------
# Függvénytár
# ----------------------------------------------------------
 
# Cím kirakó függvény
function print_title() {
    echo "Linuxportál példaprogram - Paraméterek rugalmas feldolgozása"
}
 
# Verzió kirakó függvény
function print_version() {
    echo "Verzió: $VERSION"
}
 
# Súgó kirakó függvény
function print_help() {
cat << EOF
Használat: 
$(basename $0) [kapcsoló] [érték] ... vagy
$(basename $0) [kapcsoló]=[érték] ...
Kapcsolók:
  -h,       --help          Súgó megjelenítése
  -d,       --debug         Debug mód. Ha meg van adva, akkor kiírja a futás során a használt összes kapcsoló változót.
  -v,       --version       Verzió lekérdezése
  -e1,      --egyeb1        Egyéb 1 funkció futtatása
  -e2=x,    --egyeb2=x      Egyéb 2 tároló paraméter demonstrálása
  -e3,      --egyeb3        Egyéb 3 logikai tároló paraméter demonstrálása
  -e4=x,    --egyeb4=x      Egyéb 4 tároló paraméter demonstrálása
EOF
}
 
# "Kis" súgó kirakó függvény
function print_help2() {
    echo "Súgó megjelenítése: $(basename $0) -h vagy --help"
}
 
 
# ----------------------------------------------------------
# Program indulás
# ----------------------------------------------------------
print_title                                                 # kiírjuk a címet. Ezt minden esetben kitesszük
 
 
# ----------------------------------------------------------
# Paraméterek előfeldolgozása
# ----------------------------------------------------------
 
# Nulla paraméter vizsgálata
if [[ $# -eq 0 ]] ; then                                    # Ha nem kapott paramétert a program, akkor 
    echo "${red}Hiba: Nincsenek paraméterek!${reset}" >&2  # Hibakimenetre írunk.
    print_help2                                             # Kis súgó kirakása
    exit 1                                                  # és kilépés 1-es hibakóddal
fi
 
REMAIN_PARAMETERS=()                                        # Maradék (nem várt) paraméterek tömbjének létrehozása
while [[ $# -gt 0 ]] ; do                                   # Ciklus indul, és megy, amíg maradt paraméter.
    parameter="$1"                                          # Soron következő első paraméter kiolvasása
    need_shift=0                                            # "shift szükséges" flag nullázása.
 
    # Egyenlőség jeles paraméterek kezelése
    if [[ $parameter = *"="* ]]; then                       # Ha a soron következő első paraméter tartalmaz "=" jelet, akkor
        key=${parameter%%=*}                                # a kulcs lesz az első egyenlőség jel előtti rész,
        value=${parameter#*=}                               # az érték pedig az első egyenlőség jel utáni rész.
    else                                                    # Ha a paraméterben nem volt egyenlőség jel, akkor
        key=$parameter                                      # a kulcs lesz maga a kapott paraméter
        value=$2                                            # és az utána lévő paraméter pedig lesz az esetleges érték.
        need_shift=1                                        # Itt jelezzük a lenti részeknek, hogy kell-e a plusz paraméter forgatás.
    fi
 
    # Kapcsolók elágazása
    case $key in                                            # case szerkezet: megvizsgáljuk a kulcsot, hogy mit tartalmaz.
        -h|--help)                                          # Súgó (logikai) kapcsoló érkezett...
            shift                                           # Shift-eljük (forgatjuk) a paramétereket
            PARAMS[HELP]=1                                  # Logikai érték beállítása az ennek fentartott tömb elemében.
        ;;
        -d|--debug)                                         # debug (logikai) kapcsoló ékezett...
            shift                                           # Shift-eljük (forgatjuk) a paramétereket
            PARAMS[DEBUG]=1                                 # Logikai érték beállítása az ennek fentartott tömb elemében.
        ;;
        -v|--version)                                       # verzió (logikai) kapcsoló érkezett...
            shift                                           # Shift-eljük (forgatjuk) a paramétereket
            PARAMS[VERSION]=1                               # Logikai érték beállítása az ennek fentartott tömb elemében.
        ;;
        -e1|--egyeb1)                                       # egyeb1 (logikai) kapcsoló érkezett...
            shift                                           # Shift-eljük (forgatjuk) a paramétereket
            PARAMS[EGYEB1]=1                                # Logikai érték beállítása az ennek fentartott tömb elemében.
        ;;
        -e2|--egyeb2)                                       # egyeb1 (értéket tároló) kapcsoló érkezett...
            shift                                           # Shift-eljük (forgatjuk) a paramétereket
            [[ "$value" == "" ]] && value=$escape_value     # Ha nem kapott értéket ez a kapcsoló, akkor beletesszük a menekülési értéket
            PARAMS[EGYEB2]=$value                           # a fentebb megállapított érték tárolása az ennek fentartott tömb elemében.
            [[ "$need_shift" == 1 ]] && shift               # Ha szükséges a paraméterek forgatása, akkor még egyszer forgatjuk.
        ;;
        -e3|--egyeb3)                                       # egyeb3 (logikai) kapcsoló érkezett...
            shift                                           # Shift-eljük (forgatjuk) a paramétereket
            PARAMS[EGYEB3]=1                                # Logikai érték beállítása az ennek fentartott tömb elemében.
        ;;
        -e4|--egyeb4)                                       # egyeb4 (értéket tároló) kapcsoló érkezett...
            shift                                           # Shift-eljük (forgatjuk) a paramétereket
            [[ "$value" == "" ]] && value=$escape_value     # Ha nem kapott értéket ez a kapcsoló, akkor beletesszük a menekülési értéket
            PARAMS[EGYEB4]=$value                           # a fentebb megállapított érték tárolása az ennek fentartott tömb elemében.
            [[ "$need_shift" == 1 ]] && shift               # Ha szükséges a paraméterek forgatása, akkor még egyszer forgatjuk.
        ;;
        *)                                                  # Ha ismeretlen paraméter jön a sorban, akkor
            shift                                           # Shift-eljük (forgatjuk) a paramétereket
            REMAIN_PARAMETERS+=("$key")                     # Felvesszük a kapott paramétert a maradék (nem várt) paraméterek tömbjébe.
        ;;
    esac                                                    # case vége
done                                                        # ciklus vége
# Idáig tehát "elfogyasztottuk" az összes paramétert a shift-ek által.
 
# Beállítjuk a megmaradt egyéb paramétereket a szabványos $1, $2, $3, stb változókba
# Így könnyebb a maradékot feldolgozni később, amennyiben szükséges.
set -- "${REMAIN_PARAMETERS[@]}"
 
 
# ----------------------------------------------------------
# Program futás
# ----------------------------------------------------------
 
# Debug mód. Ezt vizsgáljuk legelőször, hogy bármikor le tudjon futni
if [[ "${PARAMS[DEBUG]}" == 1 ]]; then
    echo $cyan
    echo "**********************************************"
    echo "DEBUG mód"
    echo "**********************************************"
    echo "Várt paraméterek:"
    for key in "${!PARAMS[@]}"; do echo "$key: ${PARAMS[$key]}" ; done
    echo
    echo "Nem várt paraméterek: ${REMAIN_PARAMETERS[@]}"
    echo "**********************************************"   
    echo $reset
    echo                                                    # Üres sor kihagyása
fi
 
# Súgó megjelenítése
if [[ "${PARAMS[HELP]}" == 1 ]]; then
    print_help
    echo
    exit 0
fi
 
 
# Verziószám megjelenítése
if [[ "${PARAMS[VERSION]}" == 1 ]]; then
    print_version
    echo
    exit 0
fi
 
 
# Egyéb 1 logikai kapcsoló kiértékelése és a hozzá tartozó művelet végrehajtása
if [[ "${PARAMS[EGYEB1]}" == 1 ]]; then                     # Itt csak logikai 1 értéket vizsgálunk
    # Saját műveletünk végrehajtása...
    echo "Egyéb 1 logikai kapcsoló érzékelve, művelet végrehajtása..."   # Ez ad valamilyen kimenetet...
    # ...
    # ...
 
    
    # Művelet utáni hiba kiértékelés
    result=$?                                               # Hibakód kiolvasása
    if (( $result == 0 )); then                             # Hiba kiértékelése: Ha nem volt hiba
        echo "${green}Az 'Egyéb 1' művelet sikeresen lefutott.${reset}"
#       exit 0                                              # Itt saját ízlés szerint kilépünk,
                                                            # ha nem szeretnénk további műveleteket végrehajtani ez után.
    else                                                    # Ha hiba lépett fel a műveletünk során, akkor
        echo "${red}Hiba történt az 'Egyéb 1' művelet során!${reset}" >&2
        exit 10                                             # Kilépünk egy magunk által meghatározott hibakóddal
    fi
    echo                                                    # Üres sor kihagyása
fi
 
 
# Egyéb 2 kapcsoló kiértékelése és a hozzá tartozó művelet végrehajtása
if [[ "${PARAMS[EGYEB2]}" != "" ]]; then                    # Ha bármilyen érték van benne, lefut ez a rész
 
    # Kötelező érték vizsgálata. Ez a rész opcionális, amennyiben mindenképpen várunk valamilyen értéket ebben a kapcsolóban.
    if [[ "${PARAMS[EGYEB2]}" == "$escape_value" ]]; then   # Ha a változóban a menekülési érték van benne, akkor hibával leállunk.
        echo "${red}Hiba: Az 'Egyéb 2' kapcsoló érzékelve, de nem kapott értéket!${reset}" >&2
        exit 20                                             # Kilépünk egy magunk által meghatározott hibakóddal
    fi
 
    # Saját műveletünk végrehajtása...
    echo "Egyéb 2 kapcsoló érzékelve, művelet végrehajtása..."   # Ez ad valamilyen kimenetet...
    echo "A kapott érték: '${PARAMS[EGYEB2]}'"                # Kiírjuk a kapott értéket. 
    # ...
    # ...
 
    # Művelet utáni hiba kiértékelés
    result=$?                                               # Hibakód kiolvasása
    if (( $result == 0 )); then                             # Hiba kiértékelése: Ha nem volt hiba
        echo "${green}Az 'Egyéb 2' művelet sikeresen lefutott.${reset}"
#       exit 0                                              # Itt saját ízlés szerint kilépünk,
                                                            # ha nem szeretnénk további műveleteket végrehajtani ez után.
    else                                                    # Ha hiba lépett fel a műveletünk során, akkor
        echo "${red}Hiba történt az 'Egyéb 2' művelet során!${reset}" >&2
        exit 21                                             # Kilépünk egy magunk által meghatározott hibakóddal
    fi
    echo                                                    # Üres sor kihagyása
fi
 
 
# Egyéb 3 logikai kapcsoló kiértékelése és a hozzá tartozó művelet végrehajtása
if [[ "${PARAMS[EGYEB3]}" == 1 ]]; then                     # Itt csak logikai 1 értéket vizsgálunk
    # Saját műveletünk végrehajtása...
    echo "Egyéb 3 logikai kapcsoló érzékelve, művelet végrehajtása..."   # Ez ad valamilyen kimenetet...
    # ...
    # ...
 
    # Művelet utáni hiba kiértékelés
    result=$?                                               # Hibakód kiolvasása
    if (( $result == 0 )); then                             # Hiba kiértékelése: Ha nem volt hiba
        echo "${green}Az 'Egyéb 3' művelet sikeresen lefutott.${reset}"
#       exit 0                                              # Itt saját ízlés szerint kilépünk,
                                                            # ha nem szeretnénk további műveleteket végrehajtani ez után.
    else                                                    # Ha hiba lépett fel a műveletünk során, akkor
        echo "${red}Hiba történt az 'Egyéb 3' művelet során!${reset}" >&2
        exit 30                                             # Kilépünk egy magunk által meghatározott hibakóddal
    fi
    echo                                                    # Üres sor kihagyása
fi
 
 
# Egyéb 4 kapcsoló kiértékelése és a hozzá tartozó művelet végrehajtása
if [[ "${PARAMS[EGYEB4]}" != "" ]]; then                    # Ha bármilyen érték van benne, lefut ez a rész
 
    # Kötelező érték vizsgálata. Ez a rész opcionális, amennyiben mindenképpen várunk valamilyen értéket ebben a kapcsolóban.
    if [[ "${PARAMS[EGYEB4]}" == "$escape_value" ]]; then   # Ha a változóban a menekülési érték van benne, akkor hibával leállunk.
        echo "${red}Hiba: Az 'Egyéb 4' kapcsoló érzékelve, de nem kapott értéket!${reset}" >&2
        exit 40                                             # Kilépünk egy magunk által meghatározott hibakóddal
    fi
 
    # Saját műveletünk végrehajtása...
    echo "Egyéb 4 kapcsoló érzékelve, művelet végrehajtása..."   # Ez ad valamilyen kimenetet...
    echo "A kapott érték: '${PARAMS[EGYEB4]}'"                # Kiírjuk a kapott értéket. 
    # ...
    # ...
 
    # Művelet utáni hiba kiértékelés
    result=$?                                               # Hibakód kiolvasása
    if (( $result == 0 )); then                             # Hiba kiértékelése: Ha nem volt hiba
        echo "${green}Az 'Egyéb 4' művelet sikeresen lefutott.${reset}"
#       exit 0                                              # Itt saját ízlés szerint kilépünk,
                                                            # ha nem szeretnénk további műveleteket végrehajtani ez után.
    else                                                    # Ha hiba lépett fel a műveletünk során, akkor
        echo "${red}Hiba történt az 'Egyéb 4' művelet során!${reset}" >&2
        exit 41                                             # Kilépünk egy magunk által meghatározott hibakóddal
    fi
    echo                                                    # Üres sor kihagyása
fi

 

 

Conclusion

So here is a shell script that can handle the received parameters in a flexible way as well as complete error handling. Of course, it can still be spiced with a lot of things, but it depends on the field of application for which purpose we want to create our program. It's a good idea to save it as a template and build your newly created programs into it, and the parameters are ready to be handled.

 

Related Content, Useful Links: