diff --git a/seqTemplate.sh b/seqTemplate.sh index b03bcdd..1b471d8 100755 --- a/seqTemplate.sh +++ b/seqTemplate.sh @@ -2,35 +2,31 @@ readonly toolName=mytool -# Get script working directory -# (when called from a different directory and even when called via symlink) -readonly sq_dir="$(cd "$(dirname -- "$(realpath ${BASH_SOURCE[0]})")" >>/dev/null 2>&1 && pwd)" -readonly sq_scriptFile=$(basename -- $0) -readonly sq_scriptName=${sq_scriptFile%%.*} -readonly sq_configFileName="${sq_scriptName}.cfg" -readonly sq_configFileTemplate="$sq_dir/${sq_configFileName}.example" +# Already defined by sequencer.sh, but may be overwritten +#readonly seq_configName="${sq_scriptName}.cfg" +#readonly seq_configTemplate="${seq_origin}/${sq_configName}.example" + sq_aptOpt= sq_config=0 -step_config() { +seq_config() { ## Called once before executing steps. ## e.g. to source a config file manually: - #. "$sq_config_FILE" + #. "${seq_origin}/${seq_configName}" ## or to use sequencer api with profile config file support: - #initSeqConfig -p "$sq_scriptName" "$sq_configFileTemplate" + #if initSeqConfig -p "${seq_fileName}" "${seq_configTemplate}" ; then ## or to use sequencer api with global config file: - #initSeqConfig "$sq_configFileName" "$sq_configFileTemplate" - #if [ $? -eq 0 ] ; then + #if initSeqConfig "${seq_configName}" "${seq_configTemplate}" ; then # sq_config=1 #else # # End if no configuration file exists - # [ $DRY -eq 0 ] && return -1 + # dry || return -1 #fi ## Apt cmdline option to suppress user interaction - [ $QUIET -ne 0 ] && sq_aptOpt="-y" + interactive || sq_aptOpt="-y" ## Return of non zero value will abort the sequence return 0 @@ -39,13 +35,13 @@ step_config() { step_1_info() { echoinfoArgs "[OPTIONS]"; echo "My custom step"; } step_1_alias() { echo "begin"; } step_1() { - echo "Doing something for step $1 ..." - echo "Command line arguments starting with argument 2: $@" + info "Doing something for step $1 ..." + warning "Command line arguments starting with argument 2: $*" # Use exe for regular command # Use exep "command" for commands containing pipes or redirects exe ls exep "dmesg | head" } -VERSION_SEQREV=16 +readonly sqr_minVersion=16 . /usr/local/bin/sequencer.sh diff --git a/sequencer.sh b/sequencer.sh index 1275f18..c9285bd 100755 --- a/sequencer.sh +++ b/sequencer.sh @@ -15,10 +15,10 @@ set -o pipefail ## Globals { - readonly _sqr_version=16 - readonly _sqr_versionMajor=0 - readonly _sqr_versionMinor=0 - readonly _sqr_versionString="${_sqr_version}.${_sqr_versionMajor}.${_sqr_versionMinor}" + readonly sqr_version=16 + readonly sqr_versionMajor=0 + readonly sqr_versionMinor=0 + readonly sqr_versionString="${sqr_version}.${sqr_versionMajor}.${sqr_versionMinor}" ## Seq readonly seq_name="${_sqn_alias:-${0##*/}}" @@ -28,14 +28,17 @@ set -o pipefail readonly seq_fileName=${seq_file%%.*} # shellcheck disable=SC2015 # && || is not if else readonly seq_invocation="$(printf '%q' "${0}")$( (($#)) && printf ' %q' "$@" || true)" + readonly seq_template="seqTemplate.sh" seq_args= seq_configFile= # Filled by initSeqConfig + seq_profileName= + _seq_profileList= + _seq_stepReturn=255 + # May be overwritten by seq seq_configName="${seq_fileName}.cfg" seq_configTemplate="${0%.*}.cfg.example" - seq_profileName= - _seq_profileList= ## Sequencer readonly sqr_dir="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)" @@ -44,6 +47,7 @@ set -o pipefail readonly sqr_origin="$(cd -- "$(dirname -- \ "$(readlink -f -- "${BASH_SOURCE[0]}")")" && pwd)" sqr_args= + sqr_missingConf=missingConf.log _sqr_configEdit=0 readonly _sqr_configDirName=".seqs" @@ -55,6 +59,7 @@ set -o pipefail _sqr_editor= _sqr_errno=0 _sqr_interactive=1 + _sqr_single=0 readonly _sqr_stepMax=512 _sqr_verbose=0 @@ -102,7 +107,7 @@ Usage: ${seq_name} [OPTIONS] [STEP NUMBER(s) or ALIAS] [STEP ARGUMENTS] -pl : List available profiles --quiet, -q : Don't ask for permission to execute steps If called without starting step number, only this help is shown - -qq : Same as --quiet but suppresses regular sequencer.sh output + --silent, -qq : Same as --quiet but suppresses regular sequencer.sh output --single, -s : Execute only one step If more than one step is requested, only the first will be executed --verbose, -v : Verbose output (use exe() function to call shell commands in seqs) @@ -124,9 +129,238 @@ Usage: ${seq_name} [OPTIONS] [STEP NUMBER(s) or ALIAS] [STEP ARGUMENTS] USAGE_EOF } +helpApi(){ + cat <,<,|). + Supporting: dry-run (-d): only print command without execution + verbose (-v): print command before execution + +USAGE_API + echo -e "${col_green} exep \"[COMMAND STRING(s)]\"${col_off}" + cat < \\'out put.log\\' + exep echo hello world \\> out\\\\ put.log + exep "echo hello world > 'out put.log'" + exep "echo hello world > out\\ put.log" + Important: + - Shell commands cd, read, ... won't work because [COMMAND STRING(s)] is started in a new shell. + - All apostrophes need to be esacped since the command line is given as string. + +USAGE_API + echo -e "${col_green} escpath ${col_off}" + cat < [TEMPLATE]${col_off}" + cat < [SOURCE TYPE] ${col_off}" + cat <) to a destination file. + If the CONFIGFILE exists, a backup (name_%Y%m%d-%H%M%S.bck) is saved at the same location. + If -s fails or -m, "$(realpath "${sqr_missingConf}")" is created with the conflicts + to be resolved by the user. + + -c : create a new file + -a : append to existing file + -s : skip if CONFIGFILE exists (no backup and entry in missing conf) + -m : only add content to missing conf and warn user + [SOURCE TYPE] + -f : is a file + + Text or file (-f) to create or added to + + Target file to be created or modified. + +USAGE_API + echo -e "${col_green} step ${col_off}" + cat < [DESCRIPTION]${col_off}" + cat < : Name without \$ + [DESCRIPTION] : Additional text for error output + +USAGE_API + echo -e "${col_green} saveReturn [ERRORCODE]${col_off}" + cat < 0 = fatal (stop) + readonly log_fatal=0 + readonly log_error=1 + readonly log_warning=2 + readonly log_info=3 + readonly log_debug=4 + + LOG_LEVEL="${LOG_LEVEL:-"${log_info}"}" # 4 = debug -> 0 = fatal (stop) LOG_TIME="${LOG_TIME:-}" # 1 = show time stamps # sqr::log [LOG LEVEL] [LOG_COLOR] [OPTIONS] [LOG MESSAGE] @@ -190,16 +424,16 @@ USAGE_EOF sqr::debugContinue } - stop () { sqr::log "stop" "${col_red}" "${@}"; exit 1; } - error () { [[ "${LOG_LEVEL:-0}" -ge 1 ]] && sqr::log "e" "${col_red}" "${@}"; true; } - warning () { [[ "${LOG_LEVEL:-0}" -ge 2 ]] && sqr::log "w" "${col_orange}" "${@}"; true; } - info () { [[ "${LOG_LEVEL:-0}" -ge 3 ]] && sqr::log "i" "" "${@}"; true; } - debug () { [[ "${LOG_LEVEL:-0}" -ge 4 ]] && sqr::log "dbug" "${col_lightpurple}" "${@}"; true; } + fatal () { sqr::log "stop" "${col_red}" "${@}"; exit 1; } + error () { [[ "${LOG_LEVEL:-0}" -ge ${log_error} ]] && sqr::log "e" "${col_red}" "${@}"; true; } + warning () { [[ "${LOG_LEVEL:-0}" -ge ${log_warning} ]] && sqr::log "w" "${col_orange}" "${@}"; true; } + info () { [[ "${LOG_LEVEL:-0}" -ge ${log_info} ]] && sqr::log "i" "" "${@}"; true; } + debug () { [[ "${LOG_LEVEL:-0}" -ge ${log_debug} ]] && sqr::log "dbug" "${col_lightpurple}" "${@}"; true; } # internal print(s) same loglevel as error # shellcheck disable=SC2059 # don't use variables in format - sqr::printf () { [[ "${LOG_LEVEL:-0}" -ge 1 ]] && printf "$@"; true; } - sqr::echo () { [[ "${LOG_LEVEL:-0}" -ge 1 ]] && echo "$@"; true; } + sqr::printf () { [[ "${LOG_LEVEL:-0}" -ge ${log_error} ]] && printf "$@"; true; } + sqr::echo () { [[ "${LOG_LEVEL:-0}" -ge ${log_error} ]] && echo "$@"; true; } sqr::debugPause() { if (( _sqr_debug )) ; then set +o xtrace; else true; fi @@ -283,6 +517,8 @@ USAGE_EOF ## Traps { sqr::trap_exit () { + # Only print if not silent + [[ "${LOG_LEVEL:-0}" -ge ${log_info} ]] && printf '\n%s\n' "$seq_name finished" exists -f seq_trapExit && seq_trapExit debug "Sequencer exit" } @@ -326,26 +562,21 @@ exists() { if [[ -n "${func}" ]] ; then declare -F "${func}" &>>/dev/null else - [[ -n "${!1:-}" ]] + [[ "${1:-}" =~ ^[a-zA-Z_][a-zA-Z0-9_]*$ ]] && [[ -n "${!1:-}" ]] fi } -# editor [FILE(s)..] -# Starts the detected system text editor -editor() { - "${_sqr_editor}" "$@" -} # interactive -# Started with -q to use defaults for confirmations +# Started without -q to have user interactions interactive() { (( _sqr_interactive )) } # quiet -# Log level smaller 3 (info) are treated as quiet request +# Started with -q to use defaults for confirmations quiet() { - [[ $LOG_LEVEL -lt 3 ]] + (( ! _sqr_interactive )) } # silent -# Log level equals 0 (stop) +# Log level equals 0 (fatal) silent() { [[ $LOG_LEVEL -eq 0 ]] } @@ -366,6 +597,12 @@ contextExe() { (( _sqr_contextExe )) } +# editor [FILE(s)..] +# Starts the detected system text editor +editor() { + "${_sqr_editor}" "$@" +} + ### interactive # confirm [OPTIONS] [--] [QUESTION] # Default (empty character) = no @@ -458,10 +695,12 @@ ask() { [[ -n "${answer}" ]] fi } + # Escaping non-printable characters with the proposed POSIX $'' syntax escpath() { printf "%q" "$*" } + # saveReturn # Function returns with in case step wants additional evaluation saveReturn() { @@ -549,20 +788,129 @@ endReturn() { # endIfEmpty [DESCRIPTION] # DESCRIPTION : Optional text for error endIfEmpty() { - eval 'local ref=$'"${1:-}" + local ref= + exists "${1:-}" && ref="${!1:-}" - if [ -z "${ref:-}" ] ; then + if [ -z "${ref}" ] ; then if [ -n "${2:-}" ] ; then error -- "$2" error -a "Sequence stopped." else - error -- "\${$1} must not be empty." + error -- "\${${1:-"-"}} must not be empty." error -a "Sequence stopped." fi exit 6 fi } +# addConf [FILE_MODE] +# trying to write a file +# if exists, one attempt is made to create bck file of it +# if all fails, a log file is created with the conflicts to be resolved by the user +addConf() { + local addConfBackup= + local arg + local confMode="" + local transferCmd="echo" + + for arg in "$@" ; do + case "${1:-}" in + -c) # create a new file + confMode="-c" + shift ;; + -a) # append to existing file + confMode="-a" + shift ;; + -s) # skip if CONFIGFILE exists + confMode="-s" + shift ;; + -m) # only add content to missing conf and warn user + confMode="-m" + shift ;; + -f) # choose if source is a file or text + transferCmd="cat" + shift ;; + *) # default + if [ "$confMode" == "" ] ; then + error "Parameter 1 (-a|-c|-m|-s) missing for addConf()" + exit 0 + fi ;; + esac + done + + local source="${1:?}" + local dest="${2:?}" + + if [ "${transferCmd}" == "cat" ] && [ ! -f "${source}" ] ; then + error "Source: \"${source}\" does not exist" + return 1 + fi + if dry ; then + info "Writing ${dest} ...dry-run" + return 0 + fi + if [ -z "${dest}" ] ; then + error "Destination empty" + return 1 + fi + + sqr::echo -n " [i] Writing ${dest} ..." + + if [[ ${confMode} != "-m" ]] ; then + # try writing config directly if it doesn't exist + if [ ! -f "$dest" ] ; then + "${transferCmd}" "${source}" > "${dest}" + sqr::echo "ok" + return 0 + fi + + if [[ ${confMode} == "-s" ]] ; then + # if skip is selected, don't try to backup but add confilict entry + sqr::echo "skipping (exists)" + else + # try backup existing config + addConfBackup="${dest}_$(date +%Y%m%d-%H%M%S).bck" + if [ ! -f "${addConfBackup}" ] ; then + cp -ar "${dest}" "${addConfBackup}" + if [[ ${confMode} == "-c" ]] ; then + "${transferCmd}" "${source}" > "${dest}" + else + "${transferCmd}" "${source}" >> "${dest}" + fi + sqr::echo -e "ok \n [i] Existing config saved to ${addConfBackup}" + return 0 + else + sqr::echo "nok" + warnign -e "backup exists" + fi + fi + else + sqr::echo -e "ok \n [i] no change requested" + fi + + # add configuration to missingConf file + if [[ "${missingDate:-}" = "" ]] ; then + missingDate="set" + echo -n "### " >> "${sqr_missingConf}" + date >> "${sqr_missingConf}" + fi + + local helpText="needs to be added manually" + if [[ "$confMode" == "-s" ]] ; then + helpText="not overwritten" + fi + + { + printf '#--- "%s" %s (Option: %s) ---' "${dest}" "${helpText}" "${confMode}" + "${transferCmd}" "${source}" + echo + } >> "${sqr_missingConf}" + + warning -e "Check $(realpath "${sqr_missingConf}") for configuration conflicts (${dest})" + return 1 +} + + # checkStep # return 0 - for invalid step # return Step Number @@ -571,20 +919,27 @@ endIfEmpty() { checkStep() { local checkStep_rex='^[0-9]+$' local checkStep_ref="" + local testRef= # Check if string is a number or alias if ! [[ "${1:-}" =~ ${checkStep_rex} ]] ; then - eval 'checkStep_ref=${_sqr_alias_'"${1:-}"'}' - # Catch special character after eval + if exists "_sqr_alias_${1:-}" ; then + testRef="_sqr_alias_${1:-}" + checkStep_ref="${!testRef}" + else + checkStep_ref=0 + fi + + # Catch special character after evaluation if ! [[ "${checkStep_ref}" =~ ${checkStep_rex} ]] ; then checkStep_ref=0 fi else - checkStep_ref="$1" + checkStep_ref="${1:-}" fi if (( checkStep_ref < 1 || checkStep_ref > _sqr_stepMax )) ; then - error "Invalid step: ${1:-}" + error -e "Invalid step: ${1:-}" printf '0' return 1 else @@ -593,7 +948,7 @@ checkStep() { return 0 else # step doesn't exist - error "Invalid step: ${1:-}" + error -e "Invalid step: ${1:-}" printf '0' return 1 fi @@ -625,11 +980,18 @@ parseAlias() { exists -f "step_${i}_alias" || continue # Function returns step alias - eval '_sqr_alias_'"$("step_${i}_alias")"'='"$i" + declare -g "_sqr_alias_$("step_${i}_alias")=$i" done sqr::debugContinue } +# Creating a minimal seq (step definition) template +createTemplate() { + [ -f "${seq_template}" ] && return 1 + + exe cp "${sqr_origin}/${seq_template}" "${seq_template}" +} + # displayHelp [NO TEMPLATE] [STEP NUMBER OR ALIAS] # [NO TEMPLATE] # 0 (default) : Ask for template creation @@ -683,12 +1045,11 @@ displayHelp() { printf '\n %s\n' "It seems ${0##*/} was called directly." printf ' %s\n\n' "Please create a sequence script first." if [ $createTemplate -ne 0 ] ; then - if confirm -- " Create a template now?" ; then - sqr::echo "TODO: createTemplate" - if [ $? -eq 0 ] ; then - printf '\n %s\n' "$TEMPLATE_NAME created." + if confirm " Create a template now?" ; then + if createTemplate ; then + printf '\n %s\n' "${seq_template} created." else - printf '\n %s\n' "$TEMPLATE_NAME exists...Nothing to do!" + printf '\n %s\n' "${seq_template} exists...Nothing to do!" fi else printf '\n Nothing to do!\n' @@ -793,8 +1154,8 @@ listProfiles() { # showVersion showVersion() { - printf 'Sequencer %s\n' "${_sqr_versionString}" - printf 'Seq Revision %s\n' "${VERSION_SEQREV:-"-"}" + printf 'Sequencer: %s\n' "${sqr_versionString}" + printf 'Seq needs: %s\n' "${sqr_minVersion:-"-"}" } # initSeqConfig [OPTION] [TEMPLATE] @@ -929,6 +1290,125 @@ initSeqConfig() { return $retVal } +# execute [-q] +# -q: don't stop and don't report step functions which cannot be found +# execute given step_ function +execute() { + local answer= + local notFound=0 + local noReport=0 + local stepAlias= + + if [[ "${1:-}" == "-q" ]] ; then + noReport=1 + shift + fi + + # check if step function exists + #declare -F "step_${1:?}" &>>/dev/null || notFound=1 + exists -f "step_${1:?}" || notFound=1 + if [ ${notFound} -eq 1 ] && [ ${noReport} -ne 1 ] ; then + error "Step ${1:-"-"} not found" + exit 1 + fi + + + # don't execute step functions which are not available + if (( notFound )) ; then + return 1 + fi + + if ! quiet ; then + exists -f "step_${1}_alias" && stepAlias=$("step_${1}_alias") + printf "\n [%3d] " "${1}" + if [ -n "${stepAlias}" ]; then + echo -en "${col_orange}${stepAlias}${col_off}${_sqr_savePosAlias}" + # Only add newline if step info() available + exists -f "step_${1}_info" && printf "\n%s" "${_sqr_indentExe}" + else + echo -en "${_sqr_savePosExe}" + fi + + if exists -f "step_${1}_info" ; then + _sqr_contextExe=1 + "step_${1}_info" "$1" "${seq_args[@]}" + _sqr_contextExe=0 + color none + else + # Add newline if no info is given + echo + fi + fi + + if interactive ; then + answer="$(ask "Start: (y)es/[n]o/(s)kip?" "n")" + case "${answer}" in + [yY]) + "step_$1" "$1" "${seq_args[@]}" + _seq_stepReturn="$?" ;; + [sS]) # skip step + _seq_stepReturn=0 + return 0 ;; + *) + stepAlias="${1}" + # Display alias if exists + exists -f "step_${1}_alias" && stepAlias="$("step_${1}_alias")" + + sqr::echo " [i] Stopping sequence at step: $stepAlias" + exit 1 ;; + esac + else + "step_$1" "$1" "${seq_args[@]}" + _seq_stepReturn="$?" + fi + color none +} + +# continous +# (max $_sqr_stepMax) +# execute sequence continously from given starting step +continous() { + local continous_all=0 + local continous_i + local continous_step=0 + + if [ "${1:-}" == "-a" ]; then + continous_all=1 + shift + fi + + continous_step="$(checkStep "$1")" || return 1 + + info "Starting sequence ${seq_name} ..." + + for ((continous_i=continous_step; continous_i<=_sqr_stepMax; continous_i++)); do + if ! execute -q "${continous_i}" ; then + [ ${continous_all} -eq 0 ] && break + fi + [ ${_seq_stepReturn} -ne 0 ] && break + done + return ${_seq_stepReturn} +} + +# selection +# execute given step list +# e.g.: selection -q (1, 4, 12) +selection() { + local selection_i + local selection_step=0 + local selection_array=("$@") + + [ ${#selection_array[@]} -eq 0 ] && return 1 + + info "Starting sequence ${seq_name} ..." + + for selection_i in "${selection_array[@]}" ; do + selection_step="$(checkStep "${selection_i}")" || return 1 + execute "${selection_step}" + done + return ${_seq_stepReturn} +} + # exe # Handle dry run and verbose output for commands without pipe and/or redirects exe() { @@ -956,6 +1436,26 @@ exep() { fi } +# Check if sequence is compatible +sqr::compatible() { + if [ -z "${sqr_minVersion:-}" ] ; then + warning "No sequence revision found. Trying anyway..." + else + if [ -n "${sqr_minVersion}" ] && [[ ${sqr_minVersion} -gt ${sqr_version} ]] ; then + error "Unsupported sequence revision" + showVersion + return 1 + fi + # exclude older versions if needed + if [ -n "${sqr_minVersion}" ] && [[ ${sqr_minVersion} -lt 3 ]] ; then + error "Unsupported sequence revision (addConf)" + showVersion + return 1 + fi + fi + return 0 +} + # Used as editor if no system editor could be found sqr::noEditor() { error "No editor found (\$EDITOR,\"/etc/alternatives\",nano,vi)" @@ -965,15 +1465,25 @@ sqr::noEditor() { sqr::main() { local emptyCall=1 local quickStartOne=0 + local toStart=( "0" ) + local startAll= # options check for arg in "$@" ; do case "${1:-}" in + ++) # end parameter and quickstart step 1 with -qq + quickStartOne=1 + _sqr_interactive=0 + LOG_LEVEL=0 + shift && break ;; --) # end parameter - shift && break;; + shift && break ;; + --all|-a) # execute all steps; regardless continouity + startAll="-a" + shift ;; --config|-c) # open sequence configuration file _sqr_configEdit=1 - shift;; + shift ;; --debug) _sqr_debug="1" shift ;; @@ -983,9 +1493,13 @@ sqr::main() { --help|-h) # show only help displayHelp 1 "${2:-}" exit 0 ;; + --helpapi|-ha) #show build-in functions + helpApi + exit 0;; --liststeps|-ls) shift listSteps "${1:-}" + LOG_LEVEL=0 # suppress finish message exit 0 ;; --profile|-p) # seq profile name sqr_args+=" $1 ${2:-}" @@ -1011,6 +1525,10 @@ sqr::main() { _sqr_interactive=0 LOG_LEVEL=0 shift ;; + --single|-s) # execute only one step and stop + sqr_args+=" $1" + _sqr_single=1 + shift ;; --verbose|-v) sqr_args+=" $1" _sqr_verbose=1 @@ -1028,7 +1546,7 @@ sqr::main() { # Enable error backtracing trap 'sqr::error_report "${FUNCNAME:-.}" ${LINENO}' ERR fi - + # Don't show help if only configuration should be edited [ ${_sqr_configEdit} -ne 0 ] && [ -z "${1:-}" ] && LOG_LEVEL=1 @@ -1038,18 +1556,32 @@ sqr::main() { displayHelp fi # Assume starting at one for interactive mode - START=1 + toStart=( "1" ) elif [ $quickStartOne -ne 0 ] ; then emptyCall=0 - START=1 + toStart=( "1" ) seq_args=( "$@" ) else emptyCall=0 - read -r -a START <<< "$1" + read -r -a toStart <<< "$1" shift seq_args=( "$@" ) fi + # compatibility check of sequence + sqr::compatible || exit 1 + + # dry run warning + if dry && ! quiet ; then + color yellow + echo + echo " [w] Dry run active." + echo " - Printed commands may not be accurate (e.g. quotation incorrect)" + echo " - Sequence may ignore dry run" + color none + confirm -f -n -y "Press enter to continue or Ctrl + C to abort" + fi + # Determine system default editor # Change with update-alternatives --config editor _sqr_editor="$(realpath -eq "/etc/alternatives/editor")" @@ -1080,7 +1612,7 @@ sqr::main() { [ ${emptyCall} -ne 0 ] && exit 0 fi - if checkStep "${START[0]}" >/dev/null ; then + if checkStep "${toStart[0]}" >/dev/null ; then if ! seq_config "${seq_args[@]}" ; then error "Configuring sequence failed" exit 1 @@ -1095,14 +1627,21 @@ sqr::main() { # Check for profile support if [ -n "${_seq_profileList}" ]; then - listProfiles "${_seq_profileList}"; exit $? + LOG_LEVEL=1 # suppress finish message + listProfiles "${_seq_profileList}" + exit $? elif [ -n "${seq_profileName}" ]; then listProfiles -q || exit 1 fi - sqr::printf 'Running...\n' - - step 1 "$@" + # check if more than one step is given and select execution mode + if [ ${_sqr_single} -ne 0 ] ; then + selection "${toStart[0]}" + elif [ "${#toStart[@]}" -gt "1" ]; then + selection "${toStart[@]}" + else + continous ${startAll} "${toStart[0]}" + fi } sqr::main "$@"