Add protection: do not replace // in raw://
[u/mrichter/AliRoot.git] / PWGPP / scripts / utilities.sh
1 #!/usr/bin/env bash
2 #library of useful PWGPP related bash functions
3 #it REQUIRES BASH 4 !!!!
4 #blame: Mikolaj Krzewicki, mkrzewic@cern.ch
5
6 if [ ${BASH_VERSINFO} -lt 4 ]; then
7   echo "bash version >= 4 needed, you have ${BASH_VERSION}, exiting..."
8   exit 1
9 fi
10
11 PWGPP_runMap="
12 2010 108350 139517
13 2011 140441 170593
14 2012 171590 193766
15 2013 194308 199146
16 2014 202369 206695
17 2015 999999 999999
18 2016 999999 999999
19 "
20
21 parseConfig()
22 {
23   #parse command line arguments, they have to be in the form
24   #  option=value
25   #they are then set in the environment
26   #
27   #optionally a config file can be specified in the arguments:
28   #  configFile=<someFile>
29   #config file sets variables: option=value
30   #command line options override config file
31   #
32   #recommended way of using (at the beginning of your funcion/script):
33   #  if ! parseConfig "${@}"; then return; fi
34   
35   local args=("$@")
36   local opt=""
37   
38   #first check if we will need to decode spaces
39   local encodedSpaces=""
40   for opt in "${args[@]}"; do
41     [[ "${opt}" =~ encodedSpaces=.* ]] \
42       && encodedSpaces=1 \
43       && break
44   done
45
46   #then look for a configFile (if any)
47   for opt in "${args[@]}"; do
48     if [[ ${opt} =~ configFile=.* ]]; then
49       eval "${opt}"
50       [[ ! -f ${configFile} ]] \
51         && echo "configFile ${configFile} not found, exiting..." \
52         && return 1
53       echo "using config file: ${configFile}"
54       source "${configFile}"
55       break
56     fi
57   done
58
59   #then, parse the options as they override the options from configFile
60   for opt in "${args[@]}"; do
61     [[ -n ${encodedSpaces} ]] && opt="$(decSpaces ${opt})"
62     if [[ ! "${opt}" =~ .*=.* ]]; then
63       echo "badly formatted option ${var}, should be: option=value, stopping..."
64       return 1
65     fi
66     local var="${opt%%=*}"
67     local value="${opt#*=}"
68     #echo "${var}=${value}"
69     export ${var}="${value}"
70   done
71   return 0
72 }
73
74 guessRunData()
75 {
76   #guess the period from the path, pick the rightmost one
77   #if $ocdbStorage is set it will be reset to the anchorYear (for MC)
78   period=""
79   runNumber=""
80   year=""
81   pass=""
82   legoTrainRunNumber=""
83   dataType=""
84   originalPass=""
85   originalPeriod=""
86   anchorYear=""
87   shortRunNumber=""
88
89   local oldIFS=${IFS}
90   local IFS="/"
91   [[ -z ${1} ]] && return 1
92   declare -a path=( $1 )
93   IFS="${oldIFS}"
94   local dirDepth=$(( ${#path[*]}-1 ))
95   for ((x=${dirDepth};x>=0;x--)); do
96
97     [[ $((x-1)) -ge 0 ]] && local fieldPrev=${path[$((x-1))]}
98     local field=${path[${x}]}
99     local fieldNext=${path[$((x+1))]}
100
101     [[ ${field} =~ ^[0-9]*$ && ${fieldNext} =~ (.*\.zip$|.*\.root$) ]] && legoTrainRunNumber=${field}
102     [[ -n ${legoTrainRunNumber} && -z ${pass} ]] && pass=${fieldPrev}
103     [[ ${field} =~ ^LHC[0-9][0-9][a-z].*$ ]] && period=${field%_*} && originalPeriod=${field}
104     [[ ${field} =~ ^000[0-9][0-9][0-9][0-9][0-9][0-9]$ ]] && runNumber=${field#000}
105     [[ ${field} =~ ^[0-9][0-9][0-9][0-9][0-9][0-9]$ ]] && shortRunNumber=${field}
106     [[ ${field} =~ ^20[0-9][0-9]$ ]] && year=${field}
107     [[ ${field} =~ ^(^sim$|^data$) ]] && dataType=${field}
108   done
109   originalPass=${pass}
110
111   if [[ ${dataType} =~ sim ]]; then
112     [[ -n ${shortRunNumber} && -z ${runNumber} ]] && runNumber=${shortRunNumber}
113     pass="passMC"
114     originalPass="" #for MC not from lego, the runNumber is identified as lego train number, thus needs to be nulled
115     anchorYear=$(run2year $runNumber)
116     if [[ -z "${anchorYear}" ]]; then
117       echo "WARNING: anchorYear not available for this production: ${originalPeriod}, runNumber: ${runNumber}. Cannot set the OCDB."
118       return 1
119     fi
120     #modify the OCDB: set the year
121     ocdbStorage=$(setYear ${anchorYear} ${ocdbStorage})
122   else
123     ocdbStorage=$(setYear ${year} ${ocdbStorage})
124   fi
125
126   [[ -n ${shortRunNumber} && -z ${runNumber} && -z {dataType} ]] && runNumber=${shortRunNumber}
127   [[ -n ${shortRunNumber} && "${legoTrainRunNumber}" =~ ${shortRunNumber} ]] && legoTrainRunNumber=""
128   [[ -z ${legoTrainRunNumber} && ${dataType} == "data" ]] && pass=${path[$((dirDepth-1))]}
129   [[ -n ${legoTrainRunNumber} ]] && pass+="_lego${legoTrainRunNumber}"
130   
131   #if [[ -z ${dataType} || -z ${year} || -z ${period} || -z ${runNumber}} || -z ${pass} ]];
132   if [[ -z ${runNumber} ]]
133   then
134     #error condition
135     return 1
136   fi
137   
138   #ALL OK
139   return 0
140 }
141
142 guessRunNumber()
143 (
144   #guess the run number from the path, pick the rightmost one
145   if guessRunData "${1}"; then
146     echo ${runNumber}
147     return 0
148   fi
149   return 1
150 )
151
152 guessYear()
153 (
154   #guess the year from the path, pick the rightmost one
155   if guessRunData "${1}"; then
156     echo ${year}
157     return 0
158   fi
159   return 1
160 )
161
162 guessPeriod()
163 (
164   #guess the period from the path, pick the rightmost one
165   if guessRunData "${1}"; then
166     echo ${period}
167     return 0
168   fi
169   return 1
170 )
171
172 setYear()
173 {
174   #set the year in the string
175   #usualy used to modify the year in $ocdbStorage
176   #  ${1} - year to be set
177   #  ${2} - where to set the year
178   #if AUTOYEAR is present in target - it will be replaced by the year
179   local yearSource=$(guessYearFast ${1})
180   local yearTarget=$(guessYearFast ${2})
181   local path=${2}
182   [[ ${yearSource} -ne ${yearTarget} && -n ${yearTarget} && -n ${yearSource} ]] \
183     && path=${2/\/"${yearTarget}"/\/"${yearSource}"}
184   path=${path/\/\//\/}
185   # The previous line would transform raw:// in raw:/
186   # The next fixes this
187   echo ${path/%:\//:\/\/}
188   return 0
189 }
190
191 guessYearFast()
192 {
193   #guess the year from the path, pick the rightmost one
194   #is string AUTOYEAR present, will be returned
195   local IFS="/"
196   declare -a pathArray=( ${1} )
197   local field=""
198   local year=""
199   local autoYear=""
200   for field in ${pathArray[@]}; do
201     [[ ${field} =~ ^20[0-9][0-9]$ ]] && year="${field}"
202     [[ ${field} == AUTOYEAR ]] && autoYear="${field}"
203   done
204   [[ -n ${autoYear} ]] && year="${autoYear}"
205   echo ${year}
206   return 0
207 }
208
209 run2year()
210 {
211   #for a given run print the year.
212   #the run-year table is ${PWGPP_runMap} (a string)
213   #one line per year, format: year runMin runMax
214   local run=$1
215   [[ -z ${run} ]] && return 1
216   local year=""
217   local runMin=""
218   local runMax=""
219   while read year runMin runMax; do
220     [[ -z ${year} || -z ${runMin} || -z ${runMax} ]] && continue
221     [[ ${run} -ge ${runMin} && ${run} -le ${runMax} ]] && echo ${year} && break
222   done < <(echo "${PWGPP_runMap}")
223   return 0
224 }
225
226 hostInfo(){
227 #
228 # Hallo world -  Print AliRoot/Root/Alien system info
229 #
230
231 #
232 # HOST info
233 #
234     echo --------------------------------------
235         echo 
236         echo HOSTINFO
237         echo 
238         echo HOSTINFO HOSTNAME"      "$HOSTNAME
239         echo HOSTINFO DATE"          "`date`
240         echo HOSTINFO gccpath"       "`which gcc` 
241         echo HOSTINFO gcc version"   "`gcc --version | grep gcc`
242         echo --------------------------------------    
243
244 #
245 # ROOT info
246 #
247         echo --------------------------------------
248         echo
249         echo ROOTINFO
250         echo 
251         echo ROOTINFO ROOT"           "`which root`
252         echo ROOTINFO VERSION"        "`root-config --version`
253         echo 
254         echo --------------------------------------
255
256
257 #
258 # ALIROOT info
259 #
260         echo --------------------------------------
261         echo
262         echo ALIROOTINFO
263         echo 
264         echo ALIROOTINFO ALIROOT"        "`which aliroot`
265         echo ALIROOTINFO VERSION"        "`echo $ALICE_LEVEL`
266         echo ALIROOTINFO TARGET"         "`echo $ALICE_TARGET`
267         echo 
268         echo --------------------------------------
269
270 #
271 # Alien info
272 #
273 #echo --------------------------------------
274 #echo
275 #echo ALIENINFO
276 #for a in `alien --printenv`; do echo ALIENINFO $a; done 
277 #echo
278 #echo --------------------------------------
279
280 #
281 # Local Info
282 #
283         echo PWD `pwd`
284         echo Dir 
285         ls -al
286         echo
287         echo
288         echo
289   
290   return 0
291 }
292
293 summarizeLogs()
294 {
295   #validate and summarize the status of logs
296   #input is a list of logs, or a glob:
297   #example (summarizes logs in current and subdirs):
298   #  summarizeLogs * */*
299   #if no args given, process all files in PWD
300   #exit code 1 if some logs are not validated
301
302   #print a summary of logs
303   local input
304   local file=""
305   declare -A files
306   input=("${@}")
307   [[ -z "${input[*]}" ]] && input=( "${PWD}"/* )
308   
309   #double inclusion protection+make full paths
310   for file in "${input[@]}"; do
311     [[ ! "${file}" =~ ^/ ]] && file="${PWD}/${file}"
312     files["${file}"]="${file}"
313   done
314
315   local logFiles
316   logFiles="\.*log$|^stdout$|^stderr$"
317
318   #check logs
319   local logStatus=0
320   local errorSummary=""
321   local validationStatus=""
322   declare -A coreFiles
323   for file in "${files[@]}"; do
324     [[ ! -f ${file} ]] && continue
325     #keep track of core files for later processing
326     [[ "${file##*/}" =~ ^core$ ]] && coreFiles[${file}]="${file}" && continue
327     [[ ! "${file##*/}" =~ ${logFiles} ]] && continue
328     errorSummary=$(validateLog ${file})
329     validationStatus=$?
330     [[ validationStatus -ne 0 ]] && logStatus=1
331     if [[ ${validationStatus} -eq 0 ]]; then 
332       #in pretend mode randomly report an error in rec.log some cases
333       echo "${file} OK"
334     elif [[ ${validationStatus} -eq 1 ]]; then
335       echo "${file} BAD ${errorSummary}"
336     elif [[ ${validationStatus} -eq 2 ]]; then
337       echo "${file} OK MWAH ${errorSummary}"
338     fi
339   done
340
341   #report core files
342   for x in "${coreFiles[@]}"; do
343     echo ${x}
344     chmod 644 ${x}
345     #gdb --batch --quiet -ex "bt" -ex "quit" aliroot ${x} > stacktrace_${x//\//_}.log
346     gdb --batch --quiet -ex "bt" -ex "quit" aliroot ${x} > stacktrace.log
347     local nLines[2]
348     #nLines=($(wc -l stacktrace_${x//\//_}.log))
349     nLines=($(wc -l stacktrace.log))
350     if [[ ${nLines[0]} -eq 0 ]]; then
351       #rm stacktrace_${x//\//_}.log
352       rm stacktrace.log
353     else
354       logStatus=1
355       echo "${x%/*}/stacktrace.log"
356     fi
357   done
358
359   return ${logStatus}
360 }
361
362 validateLog()
363 {
364   #validate one log file
365   #input is path to log file
366   #output an error summary on stdout
367   #exit code is 0 if validated, 1 otherwise
368   log=${1}
369   errorConditions=(
370             'There was a crash'
371             'floating'
372             'error while loading shared libraries'
373             'std::bad_alloc'
374             's_err_syswatch_'
375             'Thread [0-9]* (Thread'
376             'AliFatal'
377             '\.C.*error:.*\.h: No such file'
378             'segmentation'
379             'Segmentation fault'
380             'Interpreter error recovered'
381             ': command not found'
382             ': comando non trovato'
383             'core dumped'
384   )
385
386   warningConditions=(
387             'This is serious'
388   )
389
390   local logStatus=0
391   local errorSummary=""
392   local warningSummary=""
393   local errorCondition=""
394   for errorCondition in "${errorConditions[@]}"; do
395     local tmp=$(grep -m1 -e "${errorCondition}" ${log})
396     local error=""
397     [[ -n ${tmp} ]] && error=" : ${errorCondition}"
398     errorSummary+=${error}
399   done
400
401   local warningCondition=""
402   for warningCondition in "${warningConditions[@]}"; do
403     local tmp=$(grep -m1 -e "${warningCondition}" ${log})
404     local warning=""
405     [[ -n ${tmp} ]] && warning=" : ${warningCondition}"
406     warningSummary+=${warning}
407   done
408
409   if [[ -n ${errorSummary} ]]; then 
410     echo "${errorSummary}"
411     return 1
412   fi
413
414   if [[ -n ${warningSummary} ]]; then
415     echo "${warningSummary}"
416     return 2
417   fi
418
419   return 0
420 }
421
422 mergeSysLogs()
423 {
424   if [[ $# -lt 2 ]]; then
425     echo 'merge syslogs to an output file'
426     echo 'usage:'
427     echo 'mergeSysLogs outputFile inputFile1 inputFile2 ...'
428     return 0
429   fi
430   local outputFile
431   local inputFiles
432   local i
433   local x
434   local runNumber
435   outputFile=${1}
436   shift
437   inputFiles="$@"
438   i=0
439   if ! ls -1 ${inputFiles} &>/dev/null; then echo "the files dont exist!: ${inputFiles}"; return 1; fi
440   while read x; do 
441     runNumber=$(guessRunNumber ${x})
442     [[ -z ${runNumber} ]] && echo "run number cannot be guessed for ${x}" && continue
443     awk -v run=${runNumber} -v i=${i} 'NR > 1 {print run" "$0} NR==1 && i==0 {print "run/I:"$0}' ${x}
444     (( i++ ))
445   done < <(ls -1 ${inputFiles}) > ${outputFile}
446   return 0
447 }
448
449 stackTraceTree()
450 {
451   if [[ $# -lt 1 ]]; then
452     echo 'make stacktrace processing  in case of standard root crash log'
453     echo 'input is a (list of) text files with the stack trace (either gdb aoutput'
454     echo 'produced with e.g. gdb --batch --quiet -ex "bt" -ex "quit" aliroot core,'
455     echo 'or the root crash log), output is a TTree formatted table.'
456     echo 'example usage:'
457     echo 'benchmark.sh stackTraceTree /foo/*/rec.log'
458     echo 'benchmark.sh stackTraceTree $(cat file.list)'
459     echo 'benchmark.sh stackTraceTree `cat file.list`'
460     return 0
461   fi
462   #cat "${@}" | gawk '
463   gawk '
464        BEGIN { 
465        print "frame/I:method/C:line/C:cpass/I:aliroot/I:file/C";
466                RS="#[0-9]*";
467                aliroot=0;
468                read=1;
469              } 
470       /There was a crash/ {read=1;}
471       /The lines below might hint at the cause of the crash/ {read=0;}
472       read==1 { 
473                if ($3 ~ /Ali*/) aliroot=1; else aliroot=0;
474                gsub("#","",RT); 
475                if ($NF!="" && RT!="" && $3!="") print RT" "$3" "$NF" "0" "aliroot" "FILENAME
476              }
477       ' "${@}" 2>/dev/null
478 }
479
480 plotStackTraceTree()
481 {
482   #plot the stacktrace tree,
483   #first arg    is the text file in the root tree format
484   #second arg   is optional: a plot is written to file instead of screen
485   #third arg    is optional: selection for plotting, default skip G_ stuff
486   local tree=$1
487   local plot=${2:-"crashes.png"}
488   local selection=${3:-'!strstr(method,\"G__\")'}
489   [[ ! -f ${tree} ]] && echo "plotStackTraceTree: no input file given" && return 1
490   aliroot -b <<EOF
491 TTree* t=AliSysInfo::MakeTree("${tree}");
492 TCanvas* canvas = new TCanvas("QA crashes","QA crashes",1);
493 t->Draw("method","${selection}","");
494 canvas->SaveAs("${plot}");
495 .q
496 EOF
497   return 0
498 }
499
500 encSpaces() 
501
502   echo "${1// /±@@±}" 
503 }
504
505 decSpaces() 
506
507   echo "${1//±@@±/ }" 
508 }
509
510 get_realpath() 
511 {
512   if [[ $# -lt 1 ]]; then
513     echo "print the full path of a file or directory, like \"readlink -f\" on linux"
514     echo "Usage:"
515     echo "  get_realpath <someFileOrDir>"
516     return 0
517   fi
518   if [[ -f "$1" ]]
519   then
520     # file *must* exist
521     if cd "$(echo "${1%/*}")" &>/dev/null
522     then
523       # file *may* not be local
524       # exception is ./file.ext
525       # try 'cd .; cd -;' *works!*
526       local tmppwd="$PWD"
527       cd - &>/dev/null
528     else
529       # file *must* be local
530       local tmppwd="$PWD"
531     fi
532   elif [[ -d "$1" ]]; then
533     if cd "$1" &>/dev/null; then
534       local tmppwd="$PWD"
535       cd - &>/dev/null
536       echo "$tmppwd"
537       return 0
538     else
539       return 1
540     fi
541   else
542     # file *cannot* exist
543     return 1 # failure
544   fi
545   # reassemble realpath
546   echo "$tmppwd"/"${1##*/}"
547   return 0 # success
548 }
549
550 printLogStatistics()
551 {
552   #this function processes the summary logs and prints some stats
553   #relies on the summary log format produced by summarizeLogs()
554   # - how many checked logs in total
555   # - number of each type of problem
556   # example usage:
557   #   printLogStatistics */*.log
558   [[ ! -f $1 ]] && return 1
559   echo "log statistics from: ${1%/*}"
560   #cat "${@}" | awk '
561   awk '
562   BEGIN {nOK=0; nCores=0; nStackTraces=0;}
563   /\/core/ {nCores++}
564   /\/stacktrace.log/ {nStackTraces++}
565   /OK/ {nOK++; nLogs++;}
566   /BAD/ {
567     nLogs++
568     err=""
569     write=0
570     for (i=3; i<=NF; i++)
571     { 
572       if ($i ~ /^\:$/) 
573         write=1
574       else
575         write=0
576
577       if (write==0)
578       {
579         if (err=="") err=$i
580         else err=(err FS $i)
581       }
582
583       if (err != "" && (write==1 || i==NF))
584       {
585         sumBAD[err]++
586         err=""
587       }
588     }
589   } 
590   END {
591     print ("number of succesful jobs: " nOK" out of "nLogs )
592     for (key in sumBAD)
593     {
594       print key": "sumBAD[key]
595     }
596     if (nCores>0) print "core files: "nCores", stack traces: "nStackTraces 
597   }
598   ' "${@}"
599 }
600
601 createUniquePID()
602 {
603   #create a unique ID for jobs running in parallel
604   #consists of the ip address of the default network interface, PID,
605   #if an argument is given, append it (e.g. a production ID)
606   #the fields are space separated with a tag for easy parsing
607   #spaces in the productionID will be encoded using encSpaces()
608   local productionID=""
609   [[ -n "${1}" ]] && productionID=$(encSpaces "${1}")
610   local defaultIP=$(/sbin/route | awk '$1=="default" {print $8}' | xargs /sbin/ifconfig | awk '/inet / {print $2}' | sed 's/.*\([0-9]?\.[0-9]?\.[0-9]?\.[0-9]?\)/$1/')
611   local id="ip:${defaultIP} pid:${BASHPID}"
612   [[ -n "${productionID}" ]] && id+=" prod:${productionID}"
613   echo "${id}"
614 }
615
616 copyFileToLocal()
617 (
618   #copies a single file to a local destination: the file may either come from
619   #a local filesystem or from a remote location (whose protocol must be
620   #supported)
621   #copy is "robust" and it is repeated some times in case of failure before
622   #giving up (1 is returned in that case)
623   #origin: Dario Berzano, dario.berzano@cern.ch
624   src="$1"
625   dst="$2"
626   ok=0
627   [[ -z "${maxCopyTries}" ]] && maxCopyTries=10
628
629   proto="${src%%://*}"
630
631   echo "copy file to local dest started: $src -> $dst"
632
633   for (( i=1 ; i<=maxCopyTries ; i++ )) ; do
634
635     echo "...attempt $i of $maxCopyTries"
636     rm -f "$dst"
637
638     if [[ "$proto" == "$src" ]]; then
639       cp "$src" "$dst"
640     else
641       case "$proto" in
642         root)
643           xrdcp -f "$src" "$dst"
644         ;;
645         http)
646           curl -L "$src" -O "$dst"
647         ;;
648         *)
649           echo "protocol not supported: $proto"
650           return 2
651         ;;
652       esac
653     fi
654
655     if [ $? == 0 ] ; then
656       ok=1
657       break
658     fi
659
660   done
661
662   if [[ "$ok" == 1 ]] ; then
663     echo "copy file to local dest OK after $i attempt(s): $src -> $dst"
664     return 0
665   fi
666
667   echo "copy file to local dest FAILED after $maxCopyTries attempt(s): $src -> $dst"
668   return 1
669 )
670
671 paranoidCp()
672 (
673   #recursively copy files and directories
674   #if target is a directory - it must exist!
675   #to avoid using find and the like as they kill
676   #the performance on some cluster file systems
677   #does not copy links to avoid problems
678   sourceFiles=("${@}")
679   destination="${sourceFiles[@]:(-1)}" #last element
680   unset sourceFiles[${#sourceFiles[@]}-1] #remove last element (dst)
681   #[[ ! -f "${destination}" ]] 
682   for src in "${sourceFiles[@]}"; do
683     if [[ -f "${src}" && ! -h  "${src}" ]]; then
684       paranoidCopyFile "${src}" "${destination}"
685     elif [[ -d "${src}" && ! -h "${src}" ]]; then
686       src="${src%/}"
687       dst="${destination}/${src##*/}"
688       mkdir -p "${dst}"
689       paranoidCp "${src}"/* "${dst}"
690     fi
691   done
692 )
693
694 paranoidCopyFile()
695 (
696   #copy a single file to a target in an existing dir
697   #repeat a few times if copy fails
698   #returns 1 on failure, 0 on success
699   src=$(get_realpath "${1}")
700   dst=$(get_realpath "${2}")
701   [[ -d "${dst}" ]] && dst="${dst}/${src##*/}"
702   #some sanity check
703   [[ -z "${src}" ]] && echo "$1 does not exist" && return 1
704   [[ -z "${dst}" ]] && echo "$2 does not exist" && return 1
705   #check if we are not trying to copy to the same file
706   [[ "${src}" == "${dst}" ]] && echo "$dst==$src, not copying" && return 0
707   ok=0
708   [[ -z "${maxCopyTries}" ]] && maxCopyTries=10
709
710   echo "paranoid copy started: $src -> $dst"
711   for (( i=1 ; i<=maxCopyTries ; i++ )) ; do
712
713     echo "...attempt $i of $maxCopyTries"
714     rm -f "$dst"
715     cp "$src" "$dst"
716
717     cmp -s "$src" "$dst"
718     if [ $? == 0 ] ; then
719       ok=1
720       break
721     fi
722
723   done
724
725   if [[ "$ok" == 1 ]] ; then
726     echo "paranoid copy OK after $i attempt(s): $src -> $dst"
727     return 0
728   fi
729
730   echo "paranoid copy FAILED after $maxCopyTries attempt(s): $src -> $dst"
731   return 1
732 )
733
734 generPWD(){ 
735   #
736   # generate semirandom pwd using 2 keys 
737   # Example usage:
738   # generPWD  myserviceaccount10 key11
739   key0=$1
740   key1=$2
741   heslo0=`md5sum <<< "$key0 $key1" | cut -c 1-16`
742   heslo=`echo $heslo0 | cut -c 1-8| awk '{print toupper($0)}'`
743   heslo=$heslo`echo $heslo0 | cut -c 8-15| awk '{print tolower($0)}'`%
744   echo $heslo;
745 }
746
747 #this makes debugging easier:
748 #executes the command given as an argument in this environment
749 #use case:
750 #  bashdb utilities.sh summarizeLogs * */*
751 [[ $# != 0 ]] && eval "$@"