From 400be8581e7d61addd5b3b2295efeba8a24d6e44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B8ren=20Theilgaard?= Date: Wed, 25 Aug 2021 10:54:03 +0200 Subject: [PATCH 01/12] `checkLabels.sh` script MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With a bit of improvements to explaining that labels are small case letters with numbers, “_”, and “-”. And nothing else. --- CheckLabels.sh | 221 ++++++++++++++++++++++++++++++++++++ README.md | 4 +- utils/buildCaseStatement.sh | 9 +- 3 files changed, 229 insertions(+), 5 deletions(-) create mode 100755 CheckLabels.sh diff --git a/CheckLabels.sh b/CheckLabels.sh new file mode 100755 index 0000000..fde5da3 --- /dev/null +++ b/CheckLabels.sh @@ -0,0 +1,221 @@ +#!/bin/zsh + +# Check Installomator labels from fragments +# 2020 Søren Theilgaard (@theilgaard) + +# This script will test labels and check if download link is active, and if version is defined. +# If labels are written to the script only those will be tested. +# If none are provided, it will test all labels. + +# Labels should be named in small caps, numbers 0-9, “-”, and “_”. No other characters allowed. + +# To check this script use these labels: +# desktoppr dbeaverce brave microsoftteams whatsapp citrixworkspace aircall devonthink + + +# MARK: Constants +SELF=$(basename $0) +SELFLOCATION=$(dirname $0) +pathToLabels="fragments/labels" + +#echo "Script: $SELFLOCATION/$SELF\n" + +# MARK: check minimal macOS requirement +if [[ $(sw_vers -buildVersion ) < "18" ]]; then + echo "Installomator requires at least macOS 10.14 Mojave." + exit 98 +fi + + +# MARK: Functions + +printlog(){ + echo "$1" +} + +runAsUser() { + if [[ $currentUser != "loginwindow" ]]; then + uid=$(id -u "$currentUser") + launchctl asuser $uid sudo -u $currentUser "$@" + fi +} + +# will get the latest release download from a github repo +downloadURLFromGit() { # $1 git user name, $2 git repo name + gitusername=${1?:"no git user name"} + gitreponame=${2?:"no git repo name"} + + #githubPart="$gitusername/$gitreponame/releases/download" + #echo "$githubPart" + downloadURL="https://github.com/$gitusername/$gitreponame/releases/latest" + echo "$downloadURL" + return 0 +} + +versionFromGit() { # $1 git user name, $2 git repo name + gitusername=${1?:"no git user name"} + gitreponame=${2?:"no git repo name"} + + appNewVersion=$(curl --silent --fail "https://github.com/$gitusername/$gitreponame/releases/latest" | sed -E 's/.*tag\/(.*)\">.*/\1/g' | sed 's/[^0-9\.]//g') + if [ -z "$appNewVersion" ]; then + printlog "could not retrieve version number for $gitusername/$gitreponame: $appNewVersion" + exit 9 + else + echo "$appNewVersion" + return 0 + fi +} + + +# Handling of differences in xpath between Catalina and Big Sur +xpath() { + # the xpath tool changes in Big Sur and now requires the `-e` option + if [[ $(sw_vers -buildVersion) > "20A" ]]; then + /usr/bin/xpath -e $@ + else + /usr/bin/xpath $@ + fi +} + +# Handling architecture, so I can verify both architectures +arch () { + echo $fixedArch +} + + +# MARK: Script +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[1;34m' +NC='\033[0m' # No Color + +# Labels with the $(arch) call for different versions for Intel and Apple Silicon should be listed here: +archLabels=( $(grep "$(arch)" "${pathToLabels}"/* | awk '{print $1}' | sed -E 's/.*\/([a-z0-9\_-]*)\..*/\1/g'| uniq ) ) +echo "${BLUE}Labels with \"\$(arch)\" call:${NC}\n${archLabels}\n" + +if [[ $# -eq 0 ]]; then + allLabels=( $(ls "${pathToLabels}"/*.sh | sed -E 's/.*\/([a-z0-9\_-]*)\..*/\1/g') ) +else + allLabels=( ${=@} ) +fi +echo "${BLUE}Total labels:${NC}\n${allLabels}\n" + +secondRoundLabels="" # variable for labels with $(arch) call in them +countWarning=0 +countError=0 +for fixedArch in i386 arm64; do +echo "${BLUE}Architecture: $fixedArch${NC}" +echo + +# Go through all labels +for label in $allLabels; do + echo "########## $label" + labelWarning=0; labelError=0; expectedExtension=""; URLextension="" + name=""; type=""; downloadURL=""; appNewVersion=""; expectedTeamID=""; blockingProcesses=""; updateTool=""; updateToolArguments=""; archiveName="" + + #caseLabel + cat "${pathToLabels}/${label}.sh" | grep -v -E '^[a-z0-9\_-]*(\)|\|\\)$' | grep -v ";;" > checkLabelCurrent.sh + source checkLabelCurrent.sh + + echo "Name: $name" + echo "Download URL: $downloadURL" + echo "Type: $type" + case $type in + dmg|pkg|zip|tbz) + expectedExtension="$type" + ;; + pkgInDmg) + expectedExtension="dmg" + ;; + *InZip) + expectedExtension="zip" + ;; + *) + echo "Cannot handle type $type" + ;; + esac + if [[ "$appNewVersion" == "" ]] ; then + echo "No appNewVersion!" + else + if [[ $( echo "$appNewVersion" | grep -i "[0-9.]" ) == "" || $appNewVersion == "" ]]; then + echo "${RED}-> !! ERROR in appNewVersion${NC}" + labelError=1 + else + if [[ $appNewVersion != $( echo "$appNewVersion" | sed -E 's/[^0-9]*([0-9.]*)[^0-9]*/\1/g' ) ]]; then + echo "${YELLOW}Warning: Version contain not only numbers and dots.${NC}" + labelWarning=1 + fi + echo "Version: $appNewVersion" ; + fi + fi + if curl -sfL --output /dev/null -r 0-0 "$downloadURL" ; then + echo "${GREEN}OK: downloadURL works OK${NC}" + if [[ $(echo "$downloadURL" | sed -E 's/.*\.([a-zA-Z]*)\s*/\1/g' ) == "${expectedExtension}" ]]; then + echo "${GREEN}OK: download extension MATCH on ${expectedExtension}${NC}" + else + if [[ $(echo "$downloadURL" | grep -io "github.com") != "github.com" ]]; then + URLheader=$( curl -fsIL "$downloadURL" ) + if [[ "${URLheader}" != "" ]]; then + URLlocation=$( echo "${URLheader}" | grep -i "^location" ) + URLfilename=$( echo "${URLheader}" | grep -i "filename=" ) + if [[ "${URLlocation}" != "" ]]; then + URLextension=$( echo "${URLlocation}" | tail -1 | sed -E 's/.*\.([a-zA-Z]*)\s*/\1/g' | tr -d '\r\n' ) + else + URLextension=$( echo "${URLfilename}" | tail -1 | sed -E 's/.*\.([a-zA-Z]*)\s*/\1/g' | tr -d '\r\n' ) + fi + URLextension=${URLextension:l} + if [[ "${URLextension}" == "${expectedExtension}" ]]; then + echo "${GREEN}OK: download extension MATCH on ${URLextension}${NC}" + else + echo "${RED}-> !! ERROR in download extension, expected ${expectedExtension}, but got ${URLextension}.${NC}" + labelError=1 + fi + else + echo "no header provided from server." + fi + else + githubPart="$(echo "$downloadURL" | cut -d "/" -f4-6)" + if [[ "$(curl -fsL "$downloadURL" | grep -io "${githubPart}.*\.${expectedExtension}")" != "" ]]; then + echo "${GREEN}OK: download extension MATCH on ${expectedExtension}${NC}" + else + echo "${RED}-> !! ERROR in download extension, expected ${expectedExtension}, but it was wrong${NC}" + labelError=1 + fi + fi + fi + else + echo "${RED}-> !! ERROR in downloadURL${NC}" + labelError=1 + fi + if [[ $labelWarning != 0 ]]; then; echo "${YELLOW}########## Warning in label: $label${NC}"; ((countWarning++)); fi + if [[ $labelError != 0 ]]; then; echo "${RED}########## ERROR in label: $label${NC}"; ((countError++)); fi + + if (($archLabels[(Ie)$label])); then + secondRoundLabels+=( "$label" ) + fi + + echo +done +allLabels=( ${=secondRoundLabels} ) +archLabels=() +echo +done + +rm checkLabelCurrent.sh + +#${SELFLOCATION}/Installomator.sh version +#echo + +if [[ countWarning > 0 ]]; then + echo "${YELLOW}Warnings counted: $countWarning${NC}" +else + echo "${GREEN}No warnings detected!${NC}" +fi +if [[ countError > 0 ]]; then + echo "${RED}ERRORS counted: $countError${NC}" +else + echo "${GREEN}No errors detected!${NC}" +fi + +echo "Done!" diff --git a/README.md b/README.md index 98ac02b..8bb2b17 100644 --- a/README.md +++ b/README.md @@ -131,7 +131,9 @@ googlechrome) When you know how to extract these pieces of information from the application and/or download, then you can add an application to Installomator. -The script buildCaseStatement.sh can help with the label creation. +The script `buildCaseStatement.sh` can help with the label creation. + +Please note: Labels should be named in small caps, numbers 0-9, “-”, and “_”. No other characters allowed. ### Not specific to a management system diff --git a/utils/buildCaseStatement.sh b/utils/buildCaseStatement.sh index 81943e0..9d18ef3 100755 --- a/utils/buildCaseStatement.sh +++ b/utils/buildCaseStatement.sh @@ -122,6 +122,7 @@ elif [ "$archiveExt" = "zip" ] || [ "$archiveExt" = "tbz" ]; then fi +echo "Labels should be named in small caps, numbers 0-9, “-”, and “_”. No other characters allowed." echo echo "appNewVersion is often difficult to find. Can sometimes be found in the filename, but also on a web page. See archivePath above if link contains information about this." echo @@ -140,9 +141,9 @@ fi echo " ;;" echo -#if [ -e "${tmpDir}" ]; then -# #echo "deleting tmp dir" -# rm -rf "${tmpDir}" -#fi +if [ -e "${tmpDir}" ]; then + #echo "deleting tmp dir" + rm -rf "${tmpDir}" +fi exit 0 From 4ddc8a7f92c82b1cea727dda9a795dff1c7d1d50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B8ren=20Theilgaard?= Date: Wed, 25 Aug 2021 10:55:35 +0200 Subject: [PATCH 02/12] Update .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index ecd5e1f..4211055 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,4 @@ scratch/ # do include Installomator .pkg files #!Installomator-*.pkg +checkLabelCurrent.sh From a20770314e4b5e237b9af76bad1f9d3566377200 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B8ren=20Theilgaard?= Date: Wed, 25 Aug 2021 11:36:43 +0200 Subject: [PATCH 03/12] =?UTF-8?q?`extractLabels.sh`should=20work=20from=20?= =?UTF-8?q?=E2=80=9Cutils=E2=80=9D=20folder?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit And added description of function of script. --- utils/extractLabels.sh | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/utils/extractLabels.sh b/utils/extractLabels.sh index 264acce..332332a 100755 --- a/utils/extractLabels.sh +++ b/utils/extractLabels.sh @@ -1,9 +1,12 @@ #!/bin/zsh +# This script will create individual labels files from the original Installomator.sh script +# Only for internal use + label_re='^([a-z0-9\_-]*)(\)|\|\\)$' endlabel_re='^( |\t);;$' -label_dir="fragments/labels" +label_dir="../fragments/labels" IFS=$'\n' @@ -24,4 +27,4 @@ while read -r line; do current_label="" fi -done <./Installomator.sh +done <../Installomator.sh From 4859efa72fef6dda5dffbb5c98be67ae115882aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B8ren=20Theilgaard?= Date: Wed, 25 Aug 2021 11:49:13 +0200 Subject: [PATCH 04/12] =?UTF-8?q?Moved=20to=20=E2=80=9Cutils=E2=80=9D.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CheckLabels.sh => utils/CheckLabels.sh | 2 +- utils/extractLabels.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename CheckLabels.sh => utils/CheckLabels.sh (99%) diff --git a/CheckLabels.sh b/utils/CheckLabels.sh similarity index 99% rename from CheckLabels.sh rename to utils/CheckLabels.sh index fde5da3..c87af94 100755 --- a/CheckLabels.sh +++ b/utils/CheckLabels.sh @@ -16,7 +16,7 @@ # MARK: Constants SELF=$(basename $0) SELFLOCATION=$(dirname $0) -pathToLabels="fragments/labels" +pathToLabels=../"fragments/labels" #echo "Script: $SELFLOCATION/$SELF\n" diff --git a/utils/extractLabels.sh b/utils/extractLabels.sh index 332332a..90fac45 100755 --- a/utils/extractLabels.sh +++ b/utils/extractLabels.sh @@ -6,7 +6,7 @@ label_re='^([a-z0-9\_-]*)(\)|\|\\)$' endlabel_re='^( |\t);;$' -label_dir="../fragments/labels" +label_dir=../"fragments/labels" IFS=$'\n' From db5c9ded564ef41ab465eedc56610f2f1a91fa38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B8ren=20Theilgaard?= Date: Wed, 25 Aug 2021 11:56:23 +0200 Subject: [PATCH 05/12] Update CheckLabels.sh --- utils/CheckLabels.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/CheckLabels.sh b/utils/CheckLabels.sh index c87af94..bee2ffd 100755 --- a/utils/CheckLabels.sh +++ b/utils/CheckLabels.sh @@ -91,7 +91,7 @@ BLUE='\033[1;34m' NC='\033[0m' # No Color # Labels with the $(arch) call for different versions for Intel and Apple Silicon should be listed here: -archLabels=( $(grep "$(arch)" "${pathToLabels}"/* | awk '{print $1}' | sed -E 's/.*\/([a-z0-9\_-]*)\..*/\1/g'| uniq ) ) +archLabels=( $(grep "\$(arch)" "${pathToLabels}"/* | awk '{print $1}' | sed -E 's/.*\/([a-z0-9\_-]*)\..*/\1/g'| uniq ) ) echo "${BLUE}Labels with \"\$(arch)\" call:${NC}\n${archLabels}\n" if [[ $# -eq 0 ]]; then From 21b9709f6b12eb70ec686586c18f1e30c160a723 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B8ren=20Theilgaard?= Date: Wed, 25 Aug 2021 12:00:17 +0200 Subject: [PATCH 06/12] Renaming to `checkLabels.sh` --- utils/{CheckLabels.sh => checkLabelsTEMP.sh} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename utils/{CheckLabels.sh => checkLabelsTEMP.sh} (100%) diff --git a/utils/CheckLabels.sh b/utils/checkLabelsTEMP.sh similarity index 100% rename from utils/CheckLabels.sh rename to utils/checkLabelsTEMP.sh From 5585f8c558fc0112a690e4ef293e8d4ed80fa45f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B8ren=20Theilgaard?= Date: Wed, 25 Aug 2021 12:00:39 +0200 Subject: [PATCH 07/12] Renaming to `checkLabels.sh` --- utils/{checkLabelsTEMP.sh => checkLabels.sh} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename utils/{checkLabelsTEMP.sh => checkLabels.sh} (100%) diff --git a/utils/checkLabelsTEMP.sh b/utils/checkLabels.sh similarity index 100% rename from utils/checkLabelsTEMP.sh rename to utils/checkLabels.sh From 30bd4797ae8b056bf708e319b69307bf56d8e46a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B8ren=20Theilgaard?= Date: Wed, 25 Aug 2021 12:54:53 +0200 Subject: [PATCH 08/12] Update extractLabels.sh --- utils/extractLabels.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/extractLabels.sh b/utils/extractLabels.sh index 90fac45..904298b 100755 --- a/utils/extractLabels.sh +++ b/utils/extractLabels.sh @@ -6,7 +6,7 @@ label_re='^([a-z0-9\_-]*)(\)|\|\\)$' endlabel_re='^( |\t);;$' -label_dir=../"fragments/labels" +label_dir="fragments/labels" IFS=$'\n' From a481b17a789bb58d2b233bf75a2127c88141937d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B8ren=20Theilgaard?= Date: Wed, 25 Aug 2021 13:06:47 +0200 Subject: [PATCH 09/12] Update checkLabels.sh --- utils/checkLabels.sh | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/utils/checkLabels.sh b/utils/checkLabels.sh index bee2ffd..db412a2 100755 --- a/utils/checkLabels.sh +++ b/utils/checkLabels.sh @@ -14,13 +14,16 @@ # MARK: Constants -SELF=$(basename $0) -SELFLOCATION=$(dirname $0) -pathToLabels=../"fragments/labels" +pathToLabels="fragments/labels" -#echo "Script: $SELFLOCATION/$SELF\n" +if [[ ! -d ${pathToLabels} ]]; then + echo "This script should be called from Installomator directory as working directory with this command:" + echo "utils/checkLabels.sh" + echo + exit 99 +fi -# MARK: check minimal macOS requirement +# MARK: Check minimal macOS requirement if [[ $(sw_vers -buildVersion ) < "18" ]]; then echo "Installomator requires at least macOS 10.14 Mojave." exit 98 @@ -77,7 +80,7 @@ xpath() { fi } -# Handling architecture, so I can verify both architectures +# Handling architecture, so I can verify both i386 and arm64 architectures arch () { echo $fixedArch } @@ -91,11 +94,11 @@ BLUE='\033[1;34m' NC='\033[0m' # No Color # Labels with the $(arch) call for different versions for Intel and Apple Silicon should be listed here: -archLabels=( $(grep "\$(arch)" "${pathToLabels}"/* | awk '{print $1}' | sed -E 's/.*\/([a-z0-9\_-]*)\..*/\1/g'| uniq ) ) +archLabels=( $(grep "\$(arch)" ${pathToLabels}/* | awk '{print $1}' | sed -E 's/.*\/([a-z0-9\_-]*)\..*/\1/g'| uniq ) ) echo "${BLUE}Labels with \"\$(arch)\" call:${NC}\n${archLabels}\n" if [[ $# -eq 0 ]]; then - allLabels=( $(ls "${pathToLabels}"/*.sh | sed -E 's/.*\/([a-z0-9\_-]*)\..*/\1/g') ) + allLabels=( $(ls ${pathToLabels}/*.sh | sed -E 's/.*\/([a-z0-9\_-]*)\..*/\1/g') ) else allLabels=( ${=@} ) fi From 1d634b9a80e9f79ef38bf176f784f35f93490a81 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B8ren=20Theilgaard?= Date: Wed, 25 Aug 2021 13:16:57 +0200 Subject: [PATCH 10/12] Update buildCaseStatement.sh --- utils/buildCaseStatement.sh | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/utils/buildCaseStatement.sh b/utils/buildCaseStatement.sh index 9d18ef3..cc4594a 100755 --- a/utils/buildCaseStatement.sh +++ b/utils/buildCaseStatement.sh @@ -12,7 +12,7 @@ downloadURL=${1?:"need to provide a download URL"} # create temporary working directory -tmpDir=$(dirname $0 ) +tmpDir=$(mktemp -d ) # change directory to temporary working directory echo "Changing directory to $tmpDir" @@ -122,6 +122,9 @@ elif [ "$archiveExt" = "zip" ] || [ "$archiveExt" = "tbz" ]; then fi +echo +echo "**********" +echo echo "Labels should be named in small caps, numbers 0-9, “-”, and “_”. No other characters allowed." echo echo "appNewVersion is often difficult to find. Can sometimes be found in the filename, but also on a web page. See archivePath above if link contains information about this." @@ -140,6 +143,9 @@ echo " appName=\"$appName\"" fi echo " ;;" echo +echo "Above should be saved in a file with exact same name as label, and given extension “.sh”." +echo "Put this file in folder “fragments/labels”." +echo if [ -e "${tmpDir}" ]; then #echo "deleting tmp dir" From c37229d763a5e63f7e80917eceabde2ede0a350f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B8ren=20Theilgaard?= Date: Wed, 25 Aug 2021 13:53:17 +0200 Subject: [PATCH 11/12] Update buildCaseStatement.sh --- utils/buildCaseStatement.sh | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/utils/buildCaseStatement.sh b/utils/buildCaseStatement.sh index cc4594a..07663ba 100755 --- a/utils/buildCaseStatement.sh +++ b/utils/buildCaseStatement.sh @@ -12,7 +12,10 @@ downloadURL=${1?:"need to provide a download URL"} # create temporary working directory -tmpDir=$(mktemp -d ) +# tmpDir=$(mktemp -d ) # create a temporary folder, can be removed in the bottom of script +# tmpDir=$(dirname "$0") # (REMEMBER to comment out removal of tmpDir in bottom of script) + +tmpDir=$(pwd) # use working directory as download folder (REMEMBER to comment out removal of tmpDir in bottom of script) # change directory to temporary working directory echo "Changing directory to $tmpDir" @@ -147,9 +150,9 @@ echo "Above should be saved in a file with exact same name as label, and given e echo "Put this file in folder “fragments/labels”." echo -if [ -e "${tmpDir}" ]; then - #echo "deleting tmp dir" - rm -rf "${tmpDir}" -fi +#if [ -e "${tmpDir}" ]; then +# #echo "deleting tmp dir" +# rm -rf "${tmpDir}" +#fi exit 0 From d167a51ee69ab91d998091df73737da2a4b31753 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B8ren=20Theilgaard?= Date: Thu, 26 Aug 2021 16:14:51 +0200 Subject: [PATCH 12/12] Now reads labels from first line of label files Instead of reading the name of the file --- utils/checkLabels.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/checkLabels.sh b/utils/checkLabels.sh index db412a2..7287d7b 100755 --- a/utils/checkLabels.sh +++ b/utils/checkLabels.sh @@ -98,7 +98,7 @@ archLabels=( $(grep "\$(arch)" ${pathToLabels}/* | awk '{print $1}' | sed -E 's/ echo "${BLUE}Labels with \"\$(arch)\" call:${NC}\n${archLabels}\n" if [[ $# -eq 0 ]]; then - allLabels=( $(ls ${pathToLabels}/*.sh | sed -E 's/.*\/([a-z0-9\_-]*)\..*/\1/g') ) + allLabels=( $(grep -h -E '^([a-z0-9\_-]*)(\)|\|\\)$' ${pathToLabels}/*.sh | tr -d ')|\\' | sort) ) else allLabels=( ${=@} ) fi