-
Notifications
You must be signed in to change notification settings - Fork 11
/
execute_tasks.sh
6163 lines (5079 loc) · 187 KB
/
execute_tasks.sh
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
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
#!/usr/bin/ksh
#
# ----------------------------------------------------------------------
#H# execute_tasks.sh
#H#
#H# Function: execute one or more tasks defined in include files
#H# This is only a wrapper script with a framework to execute tasks
#H# You need at least one include file with task definitions for this script to do something useful
#H#
#h# Usage: execute_tasks.sh [-v|--verbose] [-q|--quiet] [-f|--force] [-o|--overwrite] [-y|--yes] [-n|--no] [-l|--logfile filename]
#h# [-d{:dryrun_prefix}|--dryrun{:dryrun_prefix}] [-D|--debugshell] [-t fn|--tracefunc fn] [-L]
#h# [-T|--tee] [-V|--version] [--var name=value] [--appendlog] [--nologrotate] [--noSTDOUTlog] [--disable_tty_check] [--nobackups]
#h# [--print_task_template [filename]] [--create_include_file_template [filename]] [--list [taskmask]] [--list_tasks [taskmask]]
#h# [--list_task_groups [groupmask]] [--list_default_tasks] [--abort_on_error] [--abort_on_task_not_found] [--abort_on_duplicates]
#h# [--checkonly] [--check] [--singlestep] [--unique] [--trace] [--info] [--print_includefile_help] [-i|--includefile [?]filename]
#h# [--no_init_tasks[ [--no_finish_tasks] [--only_list_tasks] [--disabled_tasks task1[...,task#]]
#H# [task1] [... task#] [-- parameter_for_init_tasks]
#h#
#H# Parameter:
#H# task#
#H# - \"task#\" can be a task to execute, a task group with multiple tasks to execute, the default task group \"all\" or \"ALL\",
#H# a pattern for tasks to execute, or an input file with a list of tasks to execute
#H#
#H# Tasks
#H# -----
#H#
#H# Each task is simply a function in one of the include files. There must be a function for every task to execute
#H# in one of the include files. The function name must start with \"task_\" but NOT with \"task_dummy\" or \"task_template\".
#H# To execute the function \"task_mytask01\" you can use the script parameter \"task_mytask01\" or \"mytask01\".
#H# If the function for a task is defined in more then one include file only the function defined
#H# in the last include file read will be used (use the parameter \"--abort_on_duplicates\" to abort the script if
#H# duplicate task definitions are found).
#H#
#H# Parameter for a task are supported; the format for tasks with parameter is: 'task#:parameter1[:...[:parameter#]]'
#H# Whitespaces (blanks or tabs) in the parameter for a task are not supported.
#H#
#H# The task names can be used with or without the leading \"task_\".
#H# In case a task and a task group use the same name the script will use the task group. To use the task
#H# instead use the task name with the leading \"task_\".
#H#
#H#
#H# Patterns
#H# --------
#H#
#H# You can also use pattern with \"*\" and \"?\" -- e.g use \"check*\" to execute all tasks beginning with \"check\".
#H#
#H#
#H# Task groups
#H# -----------
#H#
#H# Task groups are variables with a list of tasks to execute. These variables must be defined in the include files.
#H# To define a task group use the statement
#H#
#H# TASK_GROUP_<groupname>=\"task1 [... [task#]]\"
#H#
#H# in one of the include files.
#H# The prefix \"TASK_GROUP_\" is mandatory for task groups; \"<groupname>\" can be any string that is allowed
#H# for variable names in the shell executing the script. To execute the tasks in a task group use the script
#H# parameter \"<groupname>\". E.g. to execute all tasks in the task group \"TASK_GROUP_include1\" use the
#H# script parameter \"include1\".
#H#
#H# Parameter for a task group are not possible but the tasks in a task group can be defined with parameter.
#H# To use parameter define the task like this
#H#
#H# task#:parameter1[:...[:parameter#]]
#H#
#H# Note: Whitespaces in the parameter for a task in a task group are not allowed.
#H# Comments in task group definitions are allowed; comments must start with a hash \"#\" in the first column.
#H# So to add comments to a task group use a task group definition with line breaks, e.g.:
#H#
#H#TASK_GROUP_mytaskgroup001=\"# comment 1
#H## comment 2
#H## ...
#H##I# This line will be used as task info line and printed by the script
#H##I# This line also ...
#H# task1 task2 task3
#H#task4:parameter1 task5:parameter1:parameter2 task8
#H#[...]
#H# task9
#H# \"
#H#
#H# Lines starting with the prefix \"#I#\" in a task group definition will be printed if one of the parameter
#H# \"--list\", \"--list_tasks\", or \"--list_task_groups\" together with the parameter \"-v\" is used.
#H#
#H#
#H# Task group \"all\"
#H# ----------------
#H#
#H# To execute all defined tasks in all used include files use the parameter \"all\"; the tasks will then be executed
#H# in alphabetical order. If the parameter \"all\" is found all other task parameter will be ignored.
#H# Add the statement \"DISABLE_THE_PARAMETER_ALL=${__TRUE}\" to an include file to disable the parameter \"all\"
#H# (this setting can NOT be reverted in other include files).
#H#
#H# To change the list of tasks that should be executed for an include file if the parameter \"all\" is used create
#H# a variable called \"DEFAULT_TASKS\" with the list of tasks to execute for \"all\" separated by white spaces in the include file .
#H# If the variable \"DEFAULT_TASKS\" is defined in at least one include file it will be used for the parameter \"all\".
#H# If the variable \"DEFAULT_TASKS\" is defined in more then one include file the contents of the variables will be concatenated.
#H#
#H# Use the statement \"DEFAULT_TASKS=all\" in an include file to add all tasks defined in an include file to the variable
#H# \"DEFAULT_TASKS\" if that variable is defined in another include file.
#H# Add the statement \"DEFAULT_TASKS=none\" to an include file to suppress the warning about a missing definition for DEFAULT_TASKS
#H# for that include file.
#H# The use of the variable \"DEFAULT_TASK\" is also neccessary to change the order for executing the tasks.
#H# Be carefull if using include files with and without a defined variable \"DEFAULT_TASKS\"; execute the script with the parameter
#H# \"--only_list_tasks\" to check which tasks would be executed.
#H#
#H# To define tasks that should not be executed if the parameter \"all\" is used create a variable called \"NO_DEFAULT_TASKS\"
#H# in the include file with the task names. If a task is defined in the variable DEFAULT_TASKS and NO_DEFAULT_TASKS it will not
#H# be executed if \"all\" is used. You may also use patterns with \"*\" and \"?\" (like \"check_*\" or \"*003\") in the list of tasks
#H# to ignore for \"all\".
#H# If the variable \"NO_DEFAULT_TASKS\" is defined in more then one include file the contents of the variables will be concatenated.
#H#
#H#
#H# Task group \"ALL\"
#H# ----------------
#H#
#H# Use the parameter \"ALL\" to override the DEFAULT_TASKS settings from the include files and ignore the setting for
#H# DISABLE_THE_PARAMETER_ALL from all include files. If the parameter \"ALL\" is found all other task parameter will be ignored.
#H# Use the parameter \"ALL\" only if really neccessary -- in principle you should never use this parameter.
#H#
#H#
#H# Disable tasks
#H# -------------
#H#
#H# To disable one or more tasks add the tasks to the variable DISABLED_TASKS in one of the include files - the tasks in that
#H# variable will not be executed. DISABLED_TASKS can be set and changed in any function or task in the include files. This can
#H# be used to dynamically disable tasks.
#H# To not override DISABLED_TASKS defined in other include files always add new tasks to the variable, e.g.:
#H#
#H# DISABLED_TASKS=\"\${DISABLED_TASKS} [new_disabled_tasks]\"
#H#
#H# To disable one or more tasks via the parameter use the parameter \"--disabled_tasks\".
#H#
#H#
#H# Input files with tasks list
#H# ---------------------------
#H#
#H# To use an input file with the list of tasks to execute use a filename with at least one slash \"/\",
#H# e.g. \"./mytasklist\"
#H# Each line in that file must contain either a comment starting with a hash \"#\" or one task or task group to execute; e.g.:
#H#
#H##
#H## sample task input file
#H##
#H## with the list of the tasks to execute, e.g.
#H##
#H## use one blank to separate the parameter from the tasks; multiple parameter are possible;
#H## blanks or colons (:) in the parameter values are not possible)
#H##
#H#mytask0
#H#mytask1 parameter1 parameter2
#H##
#H## task groups can also be used, e.g.:
#H## parameter for the tasks are not possible if using task groups
#H##
#H#mytask_group0
#H##
#H## patterns with \"*\" and \"?\" can also be used to define tasks to execute, e.g. :
#H## parameter for the tasks are not possible if using patterns
#H##
#H#check*
#H#
#H# Empty lines and lines beginning with a \"#\" in an input file are ignored.
#H#
#H# Special tasks
#H# -------------
#H#
#H# The function \"init_tasks\" will always be executed before the first task is executed if defined in
#H# one of the include files. If \"init_tasks\" ends with a return code not equal \"${__TRUE}\" the
#H# script execution will be aborted without executing any of the tasks (use the parameter \"--no_init_tasks\" to
#H# disable the execution of the function \"init_tasks\").
#H#
#H# The function \"finish_tasks\" will always be executed after the last task is executed if defined
#H# in one of the include files (use the parameter \"--no_finish_tasks\" to disable the execution of the
#H# function \"finish_tasks\"). The return code of the function finish_tasks will be ignored.
#H#
#H# If either \"init_tasks\" or \"finish_tasks\" are defined in more then one include file only the definition
#H# from the last include file read is used.
#H#
#H#
#H# -- parameter_for_init_tasks
#H# All parameter following the separator \"--\" are parameter for the function \"init_tasks\" defined in the include file(s).
#H# Use the variable \"PARAMETER_FOR_INIT_TASKS\" in the function \"init_tasks\"to read the parameter.
#H# These parameter will be ignored by this script ${REAL_SCRIPTNAME##*/}.
#H#
#H# --includefile
#H# - name of an include file to use; the parameter can be used multiple times
#H# The parameter is optional; without the parameter \"--includefile\" the script only reads the
#H# default include file
#H# The default include file for the script
#H# \"${REAL_SCRIPTNAME##*/} \"
#H# is
#H# \"${DEFAULT_INCLUDE_FILE_NAME}\"
#H# this file is searched in the current directory and in the directory with this script
#H# \"${REAL_SCRIPTDIR}\"
#H#
#H# Note: The name of the default include file depends on the script name (which can also be a symbolic link)
#H#
#H# Use a leading question mark for the filenames of optional include files, e.g. \"-i ?my_optional_file\".
#H# Optional include files are only used if they exist.
#H# use \"--includefile none\" to delete the list of include files (including the default include file and
#H# optional include files)
#H# The script will not read the default include file if the parameter \"--includefile\" is used
#H# for at least one mandatory include file.
#H# The default include file will be read if the parameter \"--includefile\" is only used for
#H# optional include files.
#H# To read additional include files before reading the default include file add the parameter
#H# \"--includefile default\" after all other include files.
#H# The format \"--includefile:filename\" is also supported for this parameter
#H#
#H# --print_includefile_help
#H# only show the help text for all include files (these are all lines beginning with the prefix \"#H#\" in the
#H# 1st column in all include files read)
#H# --print_task_template
#H# - print the template for a new task definition to the file \"filename\" and exit. If \"filename\" is missing
#H# the template is written to STDOUT
#H# --list [pattern1[...[pattern#]]
#H# - list all defined tasks and task groups and exit; use \"-v --list \" to print also the usage help for each task
#H# if defined and the task group info for each task group if defined
#H# use one or more patterns with \"*\" and \"?\" (pattern) to only list tasks and task groups matching one of the pattern.
#H# The script will add a leading \"*\" and a trailing \"*\" to every pattern without a \"*\" and a \"?\".
#H# e.g. the pattern \"check\" will list all tasks and task groups matching the pattern \"*check*\";
#H# the pattern \"check*\" will only match the tasks and task groups matching the patterns with \"check*\".
#H# --list_tasks
#H# - like the parameter \"--list\" but only list the tasks and do not list the task groups
#H# --list_task_groups [pattern1[...[pattern#]]
#H# - list all defined task groups and exit;
#H# pattern# are (optional) patterns with \"*\" and \"?\" to list only the task groups that match one of the pattern.
#H# see the description for the parameter \"--list\" for details regarding the supported pattern.
#H# --list_default_tasks
#H# - list only the tasks that would be executed if the parameter \"all\" is used
#H# --create_include_file_template
#H# - create an include file template and exit. If \"filename\" is missing the default include file will be created.
#H# --abort_on_error
#H# - abort the task execution if a task fails, default: continue the task execution after a task failed
#H# --abort_on_task_not_found
#H# - abort the task execution if a task is not defined, default: continue the task execution with the next task
#H# --abort_on_duplicates
#H# - do not start the task execution if one or more tasks are defined multiple times; default: use the
#H# task definition found in the last include file read and ignore the other definitions
#H# use \"++abort_on_duplicates\" to suppress the warnings for duplicate task definitions
#H# --checkonly
#H# - check if all requested tasks exist and exit
#H# --check
#H# - check if all requested tasks exist before executing the tasks; exit if one or more tasks are missing
#H# --singlestep
#H# - execute the steps in single step mode
#H# --unique
#H# - execute every task only once
#H# --trace
#H# - enable trace for all tasks to execute
#H# to enable trace for only one task if multiple tasks are executed use the parameter \"-t task_<taskname>\"
#H# Tracing will only work if the function for the task starts like this
#H#
#H#function task_taskname {
#H# typeset __FUNCTION="task_taskname"
#H# \${__DEBUG_CODE}
#H# \${__FUNCTION_INIT}
#H#
#H# --info
#H# - enable verbose mode for the tasks to execute
#H# --no_init_tasks
#H# - do not execute the function \"init_tasks\"
#H# --no_finish_tasks
#H# - do not execute the function \"finish_tasks\"
#H# --only_list_tasks
#H# - only list the tasks that would be executed; init_tasks and finish_tasks will also
#H# not be executed. This parameter will not process the list of disabled tasks.
#H# To check which tasks would be executed considering the disabled tasks defined in the
#H# include files or the parameter for the script use the parameter \"-d\".
#H#
#H# --disabled_tasks
#H# Add one or more tasks to the list of disabled tasks; use blanks or commas to separate tasks;
#H# pattern for the disabled tasks are supported. This parameter can be used more then once
#H# Use \"--disabled_tasks none\" to delete the list of disabled tasks defined with this parameter
#H# also supported is the format \"--disabled_tasks:task[...]\"
#H#
#H# -h - print the script usage; use -h and -v one or more times to print more help text
#H# -v - verbose mode; use -v -v to also print the runtime system messages
#H# (or set the environment variables VERBOSE to 0 and VERBOSE_LEVEL to the level)
#H# -q - quiet mode (or set the environment variable QUIET to 0)
#H# -f - force execution (or set the environment variable FORCE to 0 )
#H# -o - eanble overwrite mode (or set the environment variable OVERWRITE to 0 )
#H# -y - answer \"yes\" to all questions
#H# -n - answer \"no\" to all questions
#H# -l - logfile to use; use "-l none" to not use a logfile at all
#H# the default logfile is /var/tmp/${SCRIPTNAME}.log
#H# also supported is the format \"-l:filename\"
#H# -d - dryrun mode, default dryrun_prefix is: \"${DEFAULT_DRYRUN_PREFIX} \"
#H# Use the parameter \"-d:<dryrun_prefix>\" or the syntax
#H# \"PREFIX=<new dryrun_prefix> ${REAL_SCRIPTNAME}\"
#H# to change the dryrun prefix
#H# The script will run in dryrun mode if the environment variable PREFIX
#H# is set. To disable that behaviour use the parameter \"+d\"
#H# Note: Is dryrun mode disabled? ${__TRUE_FALSE[${DRYRUN_MODE_DISABLED}]}
#H# -D - start a debug shell and continue the script afterwards
#H# -t - trace the function fn
#H# also supported is the format \"-t:fn[,...,fn#]\"
#H# -L - list all defined functions and end the script
#H# -T - copy STDOUT and STDERR to the file /var/tmp/${SCRIPTNAME}.$$.tee.log
#H# using tee; set the environment variable __TEE_OUTPUT_FILE before
#H# calling the script to change the file used for the output of tee
#H# -V - print the script version and exit; use \"-v -V\" to print the
#H# template version also
#H# --var
#H# - set the variable \"name\" to the value \"value\"
#H# also supported is the format \"--var:<varname>=<value>\"
#H# --appendlog
#H# - append the messages to the logfile (default: overwrite an existing logfile)
#H# This parameter also sets --nologrotate
#H# --nologrotate
#H# - do not create a backup of an existing logfile
#H# --noSTDOUTlog
#H# - do not write STDOUT/STDERR to a file if /dev/tty is not a a device
#H# --nobackups
#H# - do not create backups
#H# --disable_tty_check
#H# - disable the check if we do have a tty
#H# --nocleanup
#H# - do no house keeping at script end
#H#
#U# Parameter that toggle a switch from true to false or vice versa can
#U# be used with the plus sign (+) instead of minus (-) to invert the usage, e.g.
#U#
#U# The parameter \"-v\" enables the verbose mode; the parameter \"+v\" disables the verbose mode.
#U# The parameter \"--quiet\" enables the quiet mode; the parameter \"++quiet\" disables the quiet mode.
#U#
#U# All parameter are processed in the given order, e.g.
#U#
#U# execute_tasks.sh -v +v
#U# -> verbose mode is now off
#U#
#U# execute_tasks.sh +v -v
#U# -> verbose mode is now on
#U#
#U# Parameter are evaluated after the evaluation of environment variables, e.g
#U#
#U# VERBOSE=0 execute_tasks.sh
#U# -> verbose mode is now on
#U#
#U# VERBOSE=0 execute_tasks.sh +v
#U# -> verbose mode is now off
#U#
#U#
#U# To disable one or more of the house keeping tasks you might set some variables
#U# either before starting the script or via the parameter \"--var name=value\"
#U#
#U# The defined variables are
#U#
#U# NO_EXIT_ROUTINES=0 # do not execute the exit routines if set to 0
#U# NO_TEMPFILES_DELETE=0 # do not delete temporary files if set to 0
#U# NO_TEMPDIR_DELETE=0 # do not delete temporary directories if set to 0
#U# NO_FINISH_ROUTINES=0 # do not execute the finish routines if set to 0
#U# NO_UMOUNT_MOUNTPOINTS=0 # do not umount temporary mount points if set to 0
#U# NO_KILL_PROCS=0 # do not kill the processes if set to 0
#U#
### Predefined Return codes:
###
### 2 Invalid parameter found
### 200 Script aborted for unknown reason; EXIST signal received
### 201 Script aborted for unknown reason, QUIT signal received
### 202 This script must be executed by root only
### 203 internal error
### 250 ${SCRIPTNAME} aborted by CTRL-C
### 253 Can not create backups of the log files
### 254 ${SCRIPTNAME} aborted by the user
###
### ---------------------------------
### Note: The format of the entries for the history list should be
###
### #V# <date> v<version> <comment>
#V#
#V# History:
#V# 11.01.2019 v1.0.0 /bs
#V# initial release
#V#
#V# 17.05.2019 v1.1.0 /bs
#V# the script failed executing all tasks if the global variable "i" was used in one of the tasks -- fixed
#V# added support for a list of tasks that should not be executed if the parameter \"all\" is used (variable NO_DEFAULT_TASKS)
#V# the script now lists also all defined task groups if the parameter --list is used
#V#
#V# 29.05.2019 v1.1.1 /bs
#V# the script did not support task parameter beginning with a slash "/" -- fixed
#V#
#V# 10.07.2019 v1.1.2 /bs
#V# the script now also prints the number of tasks if the paramete "--list" is used
#V#
#V# 16.07.2019 v1.1.3 /bs
#V# added the parameter \"--list_default_tasks\"
#V#
#V# 16.08.2019 v1.1.4 /bs
#V# NO_DEFAULT_TASK now also supports the full task name, e.g. task_this_is_my_task001 and this_is_my_task001 are okay now
#V# the parameter "--list -v " now supports variables in the usage help string
#V#
#V# 12.08.2019 v1.1.5 /bs
#V# improved the output for task groups when using the parameter --list
#V#
#V# 24.08.2109 v1.2.0 /bs
#V# added the variable DISABLED_TASKS
#V#
#V# 30.09.2019 v1.3.0 /bs
#V# added optional include files
#V# added the parameter --info
#V#
#V# 25.10.2019 v1.3.1 /bs
#V# the script now only prints a small usage help if the parameter -h is used
#V# (use --help to get the long usage help like before)
#V#
#V# 01.11.2019 v1.3.2 /bs
#V# the messages about tasks that are not part of the default tasks is now only an info message and not a warning
#V#
#V# 10.11.2019 v1.3.3 /bs
#V# removed the prefix "task_" from the task names in the output
#V#
#V# 07.01.2020 v1.4.0 /bs
#V# added the parameter --no_init_tasks and --no_finish_tasks
#V# corrected some minor typos in the code and comments
#V#
#V# 14.01.2020 v1.5.0 /bs
#V# added support for parameter for the function init_tasks ( [-- parameter_for_init_tasks] )
#V# the parameter "--create_include_file_template" did not work due to a typo -- fixed
#V# input files with the list of tasks to execute did only work for filenames with absolute path -- fixed
#V# the parameter handling for tasks defined in input files with list of tasks to execute was buggy -- fixed
#V#
#V# 15.01.2020 v1.5.1 /bs
#V# their was an error in the code to process exclude masks for tasks using joker (* or ?) -- fixed
#V# the parameter "print_task_template" now supports a file for the task template
#V# the function BackupFile was buggy -- fixed
#V#
#V# 06.02.2020 v1.5.2 /bs
#V# added the parameter "--print_includefile_help"
#V#
#V# 13.02.2020 v1.5.3 /bs
#V# added the variables STARTTIME_IN_SECONDS amd STARTTIME_IN_HUMAN_READABLE_FORMAT
#V# added the variables ENDTIME_IN_SECONDS and ENDTIME_IN_HUMAN_READABLE_FORMAT
#V# added the variables RUNTIME_IN_SECONDS and RUNTIME_IN_HUMAN_READABLE_FORMAT
#V# the script now prints the start time, the runtime in seconds and in human readable format, and the return code at script end
#V#
#V# 26.06.2020 v1.5.4 /bs
#V# the variable FILES_TO_REMOVE was overwritten in the function DebugShell -- fixed
#V#
#V# 04.07.2020 v1.6.0 /bs
#V# added the variables STDIN_IS_TTY, STDOUT_IS_TTY, STDERR_IS_TTY
#V# added the variables STDIN_DEVICE, STDOUT_DEVICE, STDERR_DEVICE
#V# added the variable RUNNING_IN_A_CONSOLE_SESSION
#V# added the variable STDOUT_IS_A_PIPE
#V# added the variable STDIN_IS_A_PIPE
#V# added the variable PARENT_PROCECSS_EXECUTABLE
#V# switch_to_background did not work in Solaris -- fixed
#V# switch_to_background now ends with an error if running in an unknown OS
#V# added the parameter --disable_tty_check
#V# added the parameter nobackups
#V# added the parameter -o / --overwrite
#V# DEBUG_SHELL_CALLED was not set to ${__TRUE} in DebugShell -- fixed
#V#
#V# 04.07.2020 v1.6.0 /bs
#V# the new code from 1.6.0 did not work correct if /tmp was mounted with the option noexec -- fixed
#V#
#V# 06.07.2020 v1.6.1 /bs
#V# the script now prints the tasks names without the leading task_ if the parameter --list_default_tasks is used
#V# code to get STDIN_DEVICE and STDOUT_DEVICE rewritten
#V#
#V# 11.07.2020 v1.6.2 /bs
#V# added the parameter --list_tasks
#V# added the parameter --list_task_groups
#V#
#V# 07.08.2020 v1.6.3 /bs
#V# added the function read_file_section
#V#
#V# 17.10.2020 v2.0.0 /bs
#V# added support for comments in task groups
#V# added support for task group infos
#V# slightly enhanced the pattern usage of the parameter --list, --list_tasks, and list_task_groups
#V# added the parameter --only_list_tasks
#V# added the parameter --abort_on_duplicates
#V# added the parameter --disabled_tasks
#V# added a lot of new debug messages (printed if the parameter "-v" is used)
#V# added more details to the usage help printed with the parameter --help
#V# the handling of the variable DEFAULT_TASKS changed if more then one
#V# include file is used (see the script usage)
#V#
#T# ---------------------------------------------------------------------
#T#
#T# History of the script template
#T#
#T# 28.04.2016 v1.0.0 /bs
#T# initial release
#T#
#T# ...
#T#
#T# 08.11.2017 v2.0.0 /bs
#T# initial public release
#T#
#T# 24.11.2017 v2.1.0 /bs
#T# added the parameter -T (use tee to save the script output)
#T# added the function KillProcess
#T# the script now supports a timeout for each pid to kill at script end
#T# (see the comments for the function KillProcess)
#T# the cleanup function now supports parameter for the exit routines
#T# the cleanup function now supports parameter for the finish routines
#T# added the variable INSIDE_CLEANUP_ROUTINE
#T# added the variable INSIDE_FINISH_ROUTINE
#T# the parameter -t and the DebugShell aliase for tracing now support
#T# the variable ${.sh.func} if running in ksh93
#T# the parameter -t and the DebugShell aliase for tracing now add the statements
#T# typeset __FUNCTION=<function_name> ; ${__DEBUG_CODE};
#T# to a function if neccessary and "typeset -f" is supported by the shell used
#T# added the variable ${ENABLE_DEBUG}; if ${ENABLE_DEBUG} is not ${__TRUE} the DebugShell
#T# and the parameter -D are disabled
#T# added the variable ${USAGE_HELP}
#T# added the function show_extended_usage_help
#T# added the parameter -L / --listfunctions
#T# Read_APPL_PARAMS_entries rewritten using an array for the RCM entries
#T#
#T# 07.12.2017 v2.1.1 /bs
#T# the aliase use now only one line
#T# LogRotate now aborts the script if it can not create backups of the
#T# existing log file
#T#
#T# 10.12.2017 v2.2.0 /bs
#T# added the parameter --var, the parameter --var is disabled if the variable
#T# ${ENABLE_DEBUG} is not ${__TRUE}
#T#
#T# 19.01.2018 v2.2.1 /bs
#T# the script now uses /var/tmp/${SCRIPTNAME}.$$.STDOUT_STDERR if it can not
#T# write to the file /var/tmp/${SCRIPTNAME}.STDOUT_STDERR
#T#
#T# 29.01.2018 v2.2.2 /bs
#T# the script now uses /var/tmp/${SCRIPTNAME}.log.$$ if it can not
#T# write to the file /var/tmp/${SCRIPTNAME}.log
#T# the script now uses /var/tmp/${SCRIPTNAME}.STDOUT_STDERR.$$ if it can not
#T# write to the file /var/tmp/${SCRIPTNAME}.STDOUT_STDERR
#T#
#T# 09.02.2018 v2.2.3 /bs
#T# added the parameter --appendlog
#T# added the parameter --noSTDOUTlog
#T#
#T# 10.02.2018 v2.2.4 /bs
#T# added the parameter --nologrotate
#T#
#T# 14.02.2018 v2.2.5 /bs
#T# the script now converts the logfile name to a fully qualified name
#T# in the previous version the script created additional empty logfiles - fixed
#T#
#T# 01.04.2018 v3.0.0 /bs
#T# the parameter --var can now be used in this format also: --var:<var>=<value>
#T# the parameter --tracefunc can now be used in this format also: --tracefunc:fn[..,fn]
#T# the parameter --logfile can now be used in this format also: --logfile:<logfile>
#T# the script now prints also the template version if the parameter -v and -V are used
#T# the script now prints also the template history if the parameter "-h -v -v" are used
#T# the version of the script and the version of the template are now dynamically
#T# retrieved from the source code of the script while executing the script
#T# the parameter "-d" overwrote the value of the environment variable PREFIX -- fixed
#T# added more details to the usage help for the parameter \"-h\"
#T# added the DebugShell function editfunc
#T# added the DebugShell function savefunc
#T# added the DebugShell function restorefunc
#T# added the DebugShell function clearsavedfunc
#T# added the DebugShell function savedfuncs
#T# added the DebugShell function viewsavedfunc
#T# the function DebugShell now prints the return code of every executed command
#T# the function DebugShell did not handle "." commands with errors correct - fixed
#T# set_debug now preserves existing debug definitions if the parameter starts with a "+"
#T# the output of the DebugShell alias vi#T# 25.07.2018 v3.0.1 /bsew_debug is now more human readable
#T# the parameter --appendlog now also sets --nologrotate
#T#
#T# 25.07.2018 v3.1.0 /bs
#T# added the parameter --nocleanup
#T# added the variables
#T# NO_EXIT_ROUTINES # do not execute the exit routines if set to 0
#T# NO_TEMPFILES_DELETE # do not delete temporary files if set to 0
#T# NO_TEMPDIR_DELETE # do not delete temporary directories if set to 0
#T# NO_FINISH_ROUTINES # do not execute the finish routines if set to 0
#T# NO_KILL_PROCS # do not kill the processes if set to 0
#T# renamed the variable KSH_VERSION to __KSH_VERSION because KSH_VERSION is a
#T# readonly variable in mksh
#T#
#T# 16.08.2018 v3.2.0 /bs
#T# the default parameter processing now stops if the parameter "--" is found
#T# added code to umount temporary mount points at script end
#T# added the variable
#T# NO_UMOUNT_MOUNTPOINTS # do not umount temporary mount points at script end
#T# the cleanup function for the house keeping now does nothing in dry-run mode
#T# added the function switch_to_background to switch the process with the
#T# script into the background;
#T# this functionwas tested in Linux (RHEL), Solaris 10, AIX, and MacOS
#T#
#T# 03.11.2018 v3.2.1 /bs
#T# corrected a minor bug in the cleanup function
#T# switch_to_background disabled in the DebugShell
#T# added the variable DEBUG_SHELL_CALLED
#T# script called the finish functions twice -- fixed
#T# the script now also evaluates ${..} in help text marked with #U#
#T# (-> printed with -h -v)
#T# corrected some spelling errors
#T#
#T# 16.11.2018 v3.2.2 /bs
#T# added the variable SYSTEMD_IS_USED
#T# added the alias __getparameter to process parameter with values
#T#
#T# 08.02.2019 v3.2.3 /bs
#T# added support for ksh88 (ksh88 does not know "typeset -A" for arrays)
#T#
#T# 12.04.2019 v3.2.3 /bs
#T# the script did not get the ksh version used correct in all cases
#T#
#T#
# ----------------------------------------------------------------------
#
#
# read the template version from the source file
#
TEMPLATE_VERSION="$( grep "^#T#" $0 | grep " v[0-9]" | tail -1 | awk '{ print $3};' )"
: ${TEMPLATE_VERSION:=can not find the template version -- please check the source code of $0}
# read the script version from the source file
#
SCRIPT_VERSION="$( grep "^#V#" $0 | grep " v[0-9]" | tail -1 | awk '{ print $3};' )"
: ${SCRIPT_VERSION:=can not find the script version -- please check the source code of $0}
# list of supported include file versions
#
SUPPORTED_INCLUDE_FILE_VERSIONS="1.0.0.0"
# hardcoded script / template versions (not used anymore)
#
# TEMPLATE_VERSION="3.0.0"
# SCRIPT_VERSION="1.0.0"
# USAGE_HELP contains additional text that is written by the script if
# executed with the parameter -h
#
USAGE_HELP=""
# enviroment variables used by the script
#
ENV_VARIABLES="
PREFIX
__DEBUG_CODE
__TEE_OUTPUT_FILE
USE_ONLY_KSH88_FEATURES
BREAK_ALLOWED
EDITOR
PAGER
LOGFILE
NOHUP_STDOUT_STDERR_FILE
FORCE
QUIET
VERBOSE
VERBOSE_LEVEL
OVERWRITE
RCM_SERVICE
RCM_FUNCTION
RCM_USERID
RCM_PASSWORD
"
# define constants
#
__TRUE=0
__FALSE=1
__TRUE_FALSE[0]="true"
__TRUE_FALSE[1]="false"
# dryrun mode disabled?
# To enable dryrun mode set DRYRUN_MODE_DISABLED to ${__FALSE}
#
# dryrun mode only works if you prefix all commands that change something whith ${PREFIX}!
#
# DRYRUN_MODE_DISABLED=${__TRUE}
DRYRUN_MODE_DISABLED=${__FALSE}
# dryrun prefix (parameter -d)
#
DEFAULT_DRYRUN_PREFIX="echo "
# : ${PREFIX:=${DEFAULT_DRYRUN_PREFIX} }
: ${PREFIX:=}
# DebugShell will do nothing, and the parameter -D and --var are not usable
# if ENABLE_DEBUG is ${__FALSE}
#
ENABLE_DEBUG=${__TRUE}
#ENABLE_DEBUG=${__FALSE}
# variable for debugging
#
# use "eval ... >&2" for your debug code and use STDERR for all output!
#
# e.g.
#
# __DEBUG_CODE="eval echo \*\*\* Starting the function \$0, parameter are: \'\$*\'>&2" ./scriptt_mini.sh
#
if [ ${ENABLE_DEBUG} = ${__TRUE} ] ; then
: ${__DEBUG_CODE:=}
else
__DEBUG_CODE=""
fi
# list of functions with enabled debug code
#
__FUNCTIONS_WITH_DEBUG_CODE=""
# list of saved functions
#
__LIST_OF_SAVED_FUNCTIONS=""
# set this variable to ${__TRUE} to change the default to "tty check is disabled"
#
DISABLE_TTY_CHECK=${DISABLE_TTY_CHECK:=${__FALSE}}
RUNNING_IN_TERMINAL_SESSION=${__TRUE}
# check tty
#
if [ ${DISABLE_TTY_CHECK} = ${__FALSE} ] ; then
tty -s && RUNNING_IN_TERMINAL_SESSION=${__TRUE} || RUNNING_IN_TERMINAL_SESSION=${__FALSE}
fi
# disable the tty check if the parameter --disable_tty_check is used
#
if [[ \ $*\ == *\ --disable_tty_check\ * ]] ; then
RUNNING_IN_TERMINAL_SESSION=${__TRUE}
fi
# file for STDOUT and STDERR if the parameter -t/--tee is used
#
: ${__TEE_OUTPUT_FILE:=/var/tmp/${0##*/}.$$.tee.log}
# -----------------------------------------------------------------------------
# use the parameter -T or --tee to automatically call the script and pipe
# all output into a file using tee
if [ "${__PPID}"x = ""x ] ; then
__PPID=$PPID ; export __PPID
if [[ \ $*\ == *\ -T* || \ $*\ == *\ --tee\ * ]] ; then
echo "Saving STDOUT and STDERR to \"${__TEE_OUTPUT_FILE}\" ..."
exec $0 $@ 2>&1 | tee -a "${__TEE_OUTPUT_FILE}"
__MAINRC=$?
echo "STDOUT and STDERR saved in \"${__TEE_OUTPUT_FILE}\"."
exit ${__MAINRC}
fi
fi
: ${__PPID:=$PPID} ; export __PPID
# -----------------------------------------------------------------------------
# check for the parameter -q / --quiet
#
if [[ \ $*\ == *\ -q* || \ $*\ == *\ --quiet\ * ]] ; then
QUIET=${__TRUE}
fi
# -----------------------------------------------------------------------------
#### __KSH_VERSION - ksh version (either 88 or 93)
#### If the script is not executed by ksh the shell is compatible to
### ksh version ${__KSH_VERSION}
####
__KSH_VERSION=88 ; f() { typeset __KSH_VERSION=93 ; } ; f ;
# check if "typeset -f" is supported
#
typeset -f f | grep __KSH_VERSION >/dev/null && TYPESET_F_SUPPORTED="yes" || TYPESET_F_SUPPORTED="no"
unset -f f
# check if $0 in a function defined with "function f { ... }" is the function name
#
function f {
echo $0
}
[ "$( f )"x = "f"x ] && TRACE_FEATURE_SUPPORTED="yes" || TRACE_FEATURE_SUPPORTED="no"
unset -f f
# use ksh93 features?
#
if [ "${__KSH_VERSION}"x = "93"x ] ; then
USE_ONLY_KSH88_FEATURES=${USE_ONLY_KSH88_FEATURES:=${__FALSE}}
else
USE_ONLY_KSH88_FEATURES=${USE_ONLY_KSH88_FEATURES:=${__TRUE}}
fi
# alias to install the trap handler
#
# Note: USR1 and USR2 are different values in the various Unix OS!
#
# supported signals
#
# general signals
#
# Number KSH name Comments
# 0 EXIT This number does not correspond to a real signal, but the corresponding trap is executed before script termination.
# 1 HUP hangup
# 2 INT The interrupt signal typically is generated using the DEL or the ^C key
# 3 QUIT The quit signal is typically generated using the ^[ key. It is used like the INT signal but explicitly requests a core dump.
# 9 KILL cannot be caught or ignored
# 10 BUS bus error
# 11 SEGV segmentation violation
# 13 PIPE generated if there is a pipeline without reader to terminate the writing process(es)
# 15 TERM generated to terminate the process gracefully
# 16 USR1 user defined signal 1, this value is different in other Unix OS!
# 17 USR2 user defined signal 2, this value is different in other Unix OS!
# - DEBUG KSH only: This is no signal, but the corresponding trap code is executed before each statement of the script.
#
# signals in Solaris
# 24 SIGTSTP stop a running process (like CTRL-Z)
# 25 SIGCONT continue a stopped process in the background
#
# signals in Linux
# 20 SIGTSTP stop a running process (like CTRL-Z)
# 18 SIGCONT continue a stopped process in the background
#
# signals in AIX
# 18 SIGTSTP stop a running process (like CTRL-Z)
# 19 SIGCONT continue a stopped process in the background
#
# signals in MacOS (Darwin)
# 18 SIGTSTP stop a running process (like CTRL-Z)
# 19 SIGCONT continue a stopped process in the background
#
#
#
# Note: The usage of the variable LINENO is different in the various ksh versions
#
alias __settraps="
trap 'signal_hup_handler \${LINENO}' 1 ;\
trap 'signal_break_handler \${LINENO}' 2 ;\
trap 'signal_quit_handler \${LINENO}' 3 ;\
trap 'signal_exit_handler \${LINENO}' 15 ;\
trap 'signal_usr1_handler \${LINENO}' USR1 ;\
trap 'signal_usr2_handler \${LINENO}' USR2 ;\
"
# alias to reset all traps to the defaults
#
alias __unsettraps="
trap - 1 ;\
trap - 2 ;\
trap - 3 ;\
trap - 15 ;\
trap - USR1 ;\
trap - USR2 ;\
"
__FUNCTION_INIT="eval __settraps"
# variables used for the logfile handling
#
# the log functions save all messages in the variable LOG_MESSAGE_CACHE until the logfile to use is konwn
#
LOGFILE_FOUND=${__FALSE}
LOG_MESSAGE_CACHE=""
# variables for the trap handler
#
# The INSIDE_* variables are set to ${__TRUE} while the handler is active and
# then back to ${__FALSE} after the handler is done
#
INSIDE_DIE=${__FALSE}
INSIDE_DEBUG_SHELL=${__FALSE}
INSIDE_CLEANUP_ROUTINE=${__FALSE}
INSIDE_FINISH_ROUTINE=${__FALSE}
#
INSIDE_USR1_HANDLER=${__FALSE}
INSIDE_USR2_HANDLER=${__FALSE}
INSIDE_BREAK_HANDLER=${__FALSE}
INSIDE_HUP_HANDLER=${__FALSE}
INSIDE_EXIT_HANDLER=${__FALSE}
INSIDE_QUIT_HANDLER=${__FALSE}
# the variable DEBUG_SHELL_CALLED Is set to TRUE everytime the function DebugShell is executed
#
DEBUG_SHELL_CALLED=${__FALSE}
# set BREAK_ALLOWED to ${__FALSE} to disable CTRL-C, to ${__TRUE} to abort the script with CTRL-C
# and to "DebugShell" to call the DebugShell if the CTRL-C signal is catched
#
BREAK_ALLOWED="${BREAK_ALLOWED:=DebugShell}"
# BREAK_ALLOWED=${__FALSE}
# BREAK_ALLOWED=${__TRUE}
# current hostname
#
CUR_HOST="$( hostname )"
CUR_SHORT_HOST="${CUR_HOST%%.*}"
CUR_OS="$( uname -s )"
# script name and directory
#
typeset -r SCRIPTNAME="${0##*/}"
typeset SCRIPTDIR="${0%/*}"
if [ "${SCRIPTNAME}"x = "${SCRIPTDIR}"x ] ; then
SCRIPTDIR="$( whence ${SCRIPTNAME} )"
SCRIPTDIR="${SCRIPTDIR%/*}"
fi
REAL_SCRIPTDIR="$( cd -P ${SCRIPTDIR} ; pwd )"
REAL_SCRIPTNAME="${REAL_SCRIPTDIR}/${SCRIPTNAME}"
WORKING_DIR="$( pwd )"
LOGDIR="/var/tmp"
LOGFILE="${LOGFILE:=${LOGDIR}/${SCRIPTNAME}.log}"
CUR_SHELL="$( head -1 "${REAL_SCRIPTNAME}" | cut -f1 -d " " | cut -c3- )"
# use either vi or nano as editor if no default editor is set
#
: ${EDITOR:=$( which vi 2>/dev/null )}
: ${EDITOR:=$( which nano 2>/dev/null )}
# use less or more as pager if no default pager is set
#
: ${PAGER:=$( which less 2>/dev/null )}
: ${PAGER:=$( which more 2>/dev/null )}
SYSTEMD_IS_USED=${__FALSE}
READLINK=""
#
# if either STDIN, STDOUT, or STDERR goes to a real tty
# device this variable will be true
#
# So this is not really a bullet proof solution!
#
RUNNING_IN_A_CONSOLE_SESSION="unknown"
STDOUT_IS_A_PIPE="unknown"
STDIN_IS_A_PIPE="unknown"
[ -t 0 ] && STDIN_IS_TTY=${__TRUE} || STDIN_IS_TTY=${__FALSE}
[ -t 1 ] && STDOUT_IS_TTY=${__TRUE} || STDOUT_IS_TTY=${__FALSE}
[ -t 2 ] && STDERR_IS_TTY=${__TRUE} || STDERR_IS_TTY=${__FALSE}
STDIN_DEVICE="unknown"
STDOUT_DEVICE="unknown"
STDERR_DEVICE="unknown"
PARENT_PROCECSS_EXECUTABLE=""
case "${CUR_OS}" in
CYGWIN* )
set +o noclobber
__SHELL_FIELD=9
AWK="awk"
;;
Linux )
__SHELL_FIELD=8
ID="id"
AWK="awk"
TAR="tar"
READLINK="$( which readlink 2>/dev/null )"
ps -p 1 | grep systemd >/dev/null && SYSTEMD_IS_USED=${__TRUE} || SYSTEMD_IS_USED=${__FALSE}
[ -p /proc/$$/fd/1 ] && STDOUT_IS_A_PIPE=${__TRUE} || STDOUT_IS_A_PIPE=${__FALSE}
[ -p /proc/$$/fd/0 ] && STDIN_IS_A_PIPE=${__TRUE} || STDIN_IS_A_PIPE=${__FALSE}
TMPFILE1="/var/tmp/${SCRIPTNAME}.1.$$"
TMPFILE2="/var/tmp/${SCRIPTNAME}.2.$$"
#
# a workaround is neccessary to get the device/file used for STDOUT and STDIN in some circumstances
#
echo "( ls -l /proc/$$/fd/0 2>/dev/null || echo unknown ; ls -l /proc/$$/fd/1 2>/dev/null || echo unknown ) >${TMPFILE1}" >"${TMPFILE2}"
if [ $? -eq 0 ] ; then
chmod 755 "${TMPFILE2}"
ksh -c "${TMPFILE2}" 2>/dev/null
if [ $? -eq 0 -a -r "${TMPFILE1}" ] ; then
STDIN_DEVICE="$( head -1 "${TMPFILE1}" 2>/dev/null | awk '{ print $NF }' )"
STDOUT_DEVICE="$( tail -1 "${TMPFILE1}" 2>/dev/null | awk '{ print $NF }' )"
fi
\rm -f "${TMPFILE1}" "${TMPFILE2}" 2>/dev/null
fi
# STDIN_DEVICE="$( ls -l /proc/$$/fd/0 | awk '{ print $NF }' )"
[[ ${STDIN_DEVICE} == /dev/tty* ]] && RUNNING_IN_A_CONSOLE_SESSION=${__TRUE} || RUNNING_IN_A_CONSOLE_SESSION=${__FALSE}