diff --git a/.shellcheckrc b/.shellcheckrc new file mode 100644 index 0000000000..6eccb2a812 --- /dev/null +++ b/.shellcheckrc @@ -0,0 +1 @@ +disable=SC2002 diff --git a/Makefile b/Makefile index 02022680f4..84990a9b5c 100644 --- a/Makefile +++ b/Makefile @@ -118,6 +118,12 @@ formatf: formatc: ./tools/ormolu.sh -c +# lint all shell scripts with ShellCheck +SHELL_FILES_TO_LINT=$(shell find -not -path "./dist-newstyle/*" -not -path "./services/nginz/third_party/*" -type f -iname '*.sh') +.PHONY: shellcheck +shellcheck: + shellcheck -x $(SHELL_FILES_TO_LINT) + # For any Haskell or Rust file, update or add a license header if necessary. # Headers should be added according to Ormolu's formatting rules, but please check just in case. .PHONY: add-license diff --git a/changelog.d/5-internal/add-shellcheck-make-target b/changelog.d/5-internal/add-shellcheck-make-target new file mode 100644 index 0000000000..6e75c34214 --- /dev/null +++ b/changelog.d/5-internal/add-shellcheck-make-target @@ -0,0 +1 @@ +Add a target to the Makefile to run ShellCheck. I.e. to run a linter on all shell scripts. This will be used in the CI. diff --git a/changelog.d/mk-changelog.sh b/changelog.d/mk-changelog.sh index 550e024738..89255820eb 100755 --- a/changelog.d/mk-changelog.sh +++ b/changelog.d/mk-changelog.sh @@ -6,7 +6,7 @@ shopt -s nullglob DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" getPRNumber() { - git log --reverse --format=%s -- $1 | sed -rn '1 { /\((#.*)\)$/ s|^.*\((#.*)\)$|\1|p; }' | grep "" || + git log --reverse --format=%s -- "$1" | sed -rn '1 { /\((#.*)\)$/ s|^.*\((#.*)\)$|\1|p; }' | grep "" || echo "#PR_NOT_FOUND" } @@ -18,10 +18,13 @@ for d in "$DIR"/*; do if [[ ${#entries[@]} -eq 0 ]]; then continue; fi echo -n "## " + # shellcheck disable=SC1003 sed '$ a\' "$d/.title" echo "" for f in "${entries[@]}"; do - pr=$(getPRNumber $f) + pr=$(getPRNumber "$f") + + # shellcheck disable=SC1003 sed -r ' # create a bullet point on the first line 1 { s/^/\* /; } diff --git a/deploy/dockerephemeral/init.sh b/deploy/dockerephemeral/init.sh index eec9c37226..48182530a8 100755 --- a/deploy/dockerephemeral/init.sh +++ b/deploy/dockerephemeral/init.sh @@ -11,6 +11,7 @@ aws configure set aws_secret_access_key dummysecret aws configure set region eu-west-1 # Potentially delete pre-existing tables +# shellcheck disable=SC3037 echo -n "waiting for dynamo: " while (! aws --endpoint-url=http://dynamodb:8000 --cli-connect-timeout=1 dynamodb list-tables); do sleep 1; diff --git a/deploy/services-demo/create_team_members.sh b/deploy/services-demo/create_team_members.sh index c0fabeafe5..947421e96a 100755 --- a/deploy/services-demo/create_team_members.sh +++ b/deploy/services-demo/create_team_members.sh @@ -28,7 +28,7 @@ $ grep code out.log | grep -v email-exists If you are in a hurry, you may want to change the sleep(1) at the end of the invite loop to less than a second. If you want to give up on -the first error, add an exit(1) where we check the $INVIDATION_ID. +the first error, add an exit(1) where we check the $INVITATION_ID. " diff --git a/deploy/services-demo/create_test_team_admins.sh b/deploy/services-demo/create_test_team_admins.sh index 3e1a594ce2..6e95f9edad 100755 --- a/deploy/services-demo/create_test_team_admins.sh +++ b/deploy/services-demo/create_test_team_admins.sh @@ -46,9 +46,12 @@ fi # Generate users +# shellcheck disable=SC2034 for i in $(seq 1 "$COUNT") do + # shellcheck disable=2002 EMAIL=$(cat /dev/urandom | env LC_CTYPE=C tr -dc a-zA-Z0-9 | head -c 8)"@example.com" + # shellcheck disable=2002 PASSWORD=$(cat /dev/urandom | env LC_CTYPE=C tr -dc a-zA-Z0-9 | head -c 8) CURL_OUT=$(curl -i -s --show-error \ diff --git a/deploy/services-demo/create_test_team_members.sh b/deploy/services-demo/create_test_team_members.sh index 8f7c22643e..ab61aa4936 100755 --- a/deploy/services-demo/create_test_team_members.sh +++ b/deploy/services-demo/create_test_team_members.sh @@ -123,7 +123,7 @@ do if [ "$TEAM" != "$TEAM_UUID" ]; then echo "unexpected error: user got assigned to no / the wrong team?!" - echo ${CURL_OUT} + echo "${CURL_OUT}" exit 1 fi diff --git a/deploy/services-demo/create_test_team_scim.sh b/deploy/services-demo/create_test_team_scim.sh index b9ff961277..e852336adf 100755 --- a/deploy/services-demo/create_test_team_scim.sh +++ b/deploy/services-demo/create_test_team_scim.sh @@ -61,17 +61,17 @@ BEARER=$(curl -X POST \ --header 'Content-Type: application/json' \ --header 'Accept: application/json' \ -d '{"email":"'"$ADMIN_EMAIL"'","password":"'"$ADMIN_PASSWORD"'"}' \ - $BRIG_HOST/login'?persist=false' | jq -r .access_token) + "$BRIG_HOST/login?persist=false" | jq -r .access_token) SCIM_TOKEN_FULL=$(curl -X POST \ --header "Authorization: Bearer $BEARER" \ --header 'Content-Type: application/json;charset=utf-8' \ --header 'Z-User: '"$ADMIN_UUID" \ - -d '{ "description": "test '"`date`"'", "password": "'"$ADMIN_PASSWORD"'" }' \ - $SPAR_HOST/scim/auth-tokens) + -d '{ "description": "test '"$(date)"'", "password": "'"$ADMIN_PASSWORD"'" }' \ + "$SPAR_HOST/scim/auth-tokens") -SCIM_TOKEN=$(echo $SCIM_TOKEN_FULL | jq -r .token) -SCIM_TOKEN_ID=$(echo $SCIM_TOKEN_FULL | jq -r .info.id) +SCIM_TOKEN=$(echo "$SCIM_TOKEN_FULL" | jq -r .token) +SCIM_TOKEN_ID=$(echo "$SCIM_TOKEN_FULL" | jq -r .info.id) # Create regular user via team invitation @@ -156,7 +156,7 @@ CURL_OUT_SCIM_POST=$(curl --location --request POST "$SPAR_HOST/scim/v2/Users" \ --header "Authorization: Bearer $SCIM_TOKEN" \ -d "$SCIM_USER") -SCIM_USER_UUID=$(echo $CURL_OUT_SCIM_POST | jq -r .id) +SCIM_USER_UUID=$(echo "$CURL_OUT_SCIM_POST" | jq -r .id) SCIM_USER_INVITATION_ID=$(curl --location -G "$BRIG_HOST/i/teams/invitations/by-email?" \ --header 'Content-Type: application/json' \ @@ -186,13 +186,13 @@ EOF CURL_OUT=$(curl \ -XPOST "$BRIG_HOST/i/users" \ -H'Content-type: application/json' \ - -d'{"email":"'"$scimUserEmail"'","password":"'"$scimUserPassword"'","name":"'"$scimUserDisplayName"'","team_code":"'"$SCIM_USER_INVITATION_CODE"'"}') + -d"$REGISTER_ACCEPT") SCIM_USER_REGISTER_TEAM=$(echo "$CURL_OUT" | jq -r .team) if [ "$SCIM_USER_REGISTER_TEAM" != "$TEAM_UUID" ]; then echo "unexpected error: user got assigned to no / the wrong team?!" - echo ${CURL_OUT} + echo "${CURL_OUT}" exit 1 fi diff --git a/deploy/services-demo/create_test_user.sh b/deploy/services-demo/create_test_user.sh index 9769cff402..5d44e8098d 100755 --- a/deploy/services-demo/create_test_user.sh +++ b/deploy/services-demo/create_test_user.sh @@ -45,7 +45,8 @@ fi; # Generate users -for i in `seq 1 $COUNT` +# shellcheck disable=SC2034 +for i in $(seq 1 "$COUNT") do EMAIL=$(cat /dev/urandom | env LC_CTYPE=C tr -dc a-zA-Z0-9 | head -c 8)"@example.com" PASSWORD=$(cat /dev/urandom | env LC_CTYPE=C tr -dc a-zA-Z0-9 | head -c 8) @@ -53,12 +54,12 @@ do CURL_OUT=$(curl -i -s --show-error \ -XPOST "$BRIG_HOST/i/users" \ -H'Content-type: application/json' \ - -d'{"email":"'$EMAIL'","password":"'$PASSWORD'","name":"demo"}') + -d'{"email":"'"$EMAIL"'","password":"'"$PASSWORD"'","name":"demo"}') UUID=$(echo "$CURL_OUT" | tail -1 | sed 's/.*\"id\":\"\([a-z0-9-]*\)\".*/\1/') if [ "$CSV" == "false" ] - then echo -e "Succesfully created a user with email: "$EMAIL" and password: "$PASSWORD - else echo -e $UUID","$EMAIL","$PASSWORD + then echo -e "Succesfully created a user with email: $EMAIL and password: $PASSWORD" + else echo -e "$UUID,$EMAIL,$PASSWORD" fi done diff --git a/deploy/services-demo/demo.sh b/deploy/services-demo/demo.sh index 564bb045ce..daac579b11 100755 --- a/deploy/services-demo/demo.sh +++ b/deploy/services-demo/demo.sh @@ -4,6 +4,7 @@ set -eo pipefail +# shellcheck disable=SC2034 USAGE="$0 [docker] [--run-backoffice]" docker_deployment="false" if [ "$1" = "docker" ] || [ "$2" = "docker" ] ; then @@ -27,7 +28,8 @@ function kill_all() { } function list_descendants () { - local children=$(pgrep -P "$1") + local children + children=$(pgrep -P "$1") for pid in $children do list_descendants "$pid" @@ -38,14 +40,14 @@ function list_descendants () { function kill_gracefully() { pkill "gundeck|brig|galley|cargohold|cannon|spar|stern" sleep 1 - kill $(list_descendants $PARENT_PID) &> /dev/null + kill "$(list_descendants $PARENT_PID)" &> /dev/null } function run_zauth() { if [ "$docker_deployment" = "false" ]; then - ${DIR}/../dist/zauth "$@" + "${DIR}/../dist/zauth" "$@" else - docker run --entrypoint "/usr/bin/zauth" ${docker_zauth_image:-quay.io/wire/zauth} $@ + docker run --entrypoint "/usr/bin/zauth" "${docker_zauth_image:-quay.io/wire/zauth}" "$@" fi } @@ -53,47 +55,51 @@ trap "kill_gracefully; kill_all" INT TERM ERR function check_secrets() { if [ "$docker_deployment" = "false" ]; then - test -f ${DIR}/../dist/zauth || { echo "zauth is not compiled. How about you run 'cd ${TOP_LEVEL} && make services' first?"; exit 1; } + test -f "${DIR}/../dist/zauth" || { echo "zauth is not compiled. How about you run 'cd ${TOP_LEVEL} && make services' first?"; exit 1; } fi if [[ ! -f ${SCRIPT_DIR}/resources/turn/secret.txt ]]; then echo "Generate a secret for the TURN servers (must match the turn.secret key in brig's config)..." - openssl rand -base64 64 | env LC_CTYPE=C tr -dc a-zA-Z0-9 | head -c 42 > ${SCRIPT_DIR}/resources/turn/secret.txt + openssl rand -base64 64 | env LC_CTYPE=C tr -dc a-zA-Z0-9 | head -c 42 > "${SCRIPT_DIR}/resources/turn/secret.txt" else echo "re-using existing TURN secret" fi if [[ ! -f ${SCRIPT_DIR}/resources/zauth/privkeys.txt || ! -f ${SCRIPT_DIR}/resources/zauth/pubkeys.txt ]]; then echo "Generate private and public keys (used both by brig and nginz)..." - mkdir -p ${SCRIPT_DIR}/resources/zauth/ + mkdir -p "${SCRIPT_DIR}/resources/zauth/" TMP_KEYS=$(mktemp "/tmp/demo.keys.XXXXXXXXXXX") - run_zauth -m gen-keypair -i 1 > $TMP_KEYS - cat $TMP_KEYS | sed -n 's/public: \(.*\)/\1/p' > ${SCRIPT_DIR}/resources/zauth/pubkeys.txt - cat $TMP_KEYS | sed -n 's/secret: \(.*\)/\1/p' > ${SCRIPT_DIR}/resources/zauth/privkeys.txt + run_zauth -m gen-keypair -i 1 > "$TMP_KEYS" + cat "$TMP_KEYS" | sed -n 's/public: \(.*\)/\1/p' > "${SCRIPT_DIR}/resources/zauth/pubkeys.txt" + cat "$TMP_KEYS" | sed -n 's/secret: \(.*\)/\1/p' > "${SCRIPT_DIR}/resources/zauth/privkeys.txt" else echo "re-using existing public/private keys" fi } function check_prerequisites() { + + # shellcheck disable=SC2015 nc -z 127.0.0.1 9042 \ && nc -z 127.0.0.1 9200 \ && nc -z 127.0.0.1 6379 \ || { echo "Databases not up. Maybe run 'deploy/dockerephemeral/run.sh' in a separate terminal first?"; exit 1; } if [ "$docker_deployment" = "false" ]; then - test -f ${DIR}/../dist/brig \ - && test -f ${DIR}/../dist/galley \ - && test -f ${DIR}/../dist/cannon \ - && test -f ${DIR}/../dist/gundeck \ - && test -f ${DIR}/../dist/cargohold \ - && test -f ${DIR}/../dist/proxy \ - && test -f ${DIR}/../dist/spar \ - && test -f ${DIR}/../dist/stern \ - && ( test -f ${DIR}/../dist/nginx || which nix-build ) \ + # shellcheck disable=SC2015 + test -f "${DIR}/../dist/brig" \ + && test -f "${DIR}/../dist/galley" \ + && test -f "${DIR}/../dist/cannon" \ + && test -f "${DIR}/../dist/gundeck" \ + && test -f "${DIR}/../dist/cargohold" \ + && test -f "${DIR}/../dist/proxy" \ + && test -f "${DIR}/../dist/spar" \ + && test -f "${DIR}/../dist/stern" \ + && ( test -f "${DIR}/../dist/nginx" || which nix-build ) \ || { echo "Not all services are compiled. How about you run 'cd ${TOP_LEVEL} && make services' first?"; exit 1; } fi } blue=6 +# shellcheck disable=SC2034 white=7 green=10 orange=3 @@ -105,8 +111,9 @@ blueish=4 function run_haskell_service() { service=$1 colour=$2 - (cd ${SCRIPT_DIR} && ${DIR}/../dist/${service} -c ${SCRIPT_DIR}/conf/${service}.demo.yaml || kill_all) \ - | sed -e "s/^/$(tput setaf ${colour})[${service}] /" -e "s/$/$(tput sgr0)/" & + # shellcheck disable=SC2015 + (cd "${SCRIPT_DIR}" && "${DIR}/../dist/${service}" -c "${SCRIPT_DIR}/conf/${service}.demo.yaml" || kill_all) \ + | sed -e "s/^/$(tput setaf "${colour}")[${service}] /" -e "s/$/$(tput sgr0)/" & } function run_nginz() { @@ -117,12 +124,14 @@ function run_nginz() { # nix-build will put a symlink to ./result with the nginx artifact if which nix-build; then nginz=$(nix-build "${DIR}/../nix" -A nginz --no-out-link ) - (cd ${SCRIPT_DIR} && ${nginz}/bin/nginx -p ${SCRIPT_DIR} -c ${SCRIPT_DIR}/conf/nginz/nginx.conf -g 'daemon off;' || kill_all) \ - | sed -e "s/^/$(tput setaf ${colour})[nginz] /" -e "s/$/$(tput sgr0)/" & + # shellcheck disable=SC2015 + (cd "${SCRIPT_DIR}" && "${nginz}/bin/nginx" -p "${SCRIPT_DIR}" -c "${SCRIPT_DIR}/conf/nginz/nginx.conf" -g 'daemon off;' || kill_all) \ + | sed -e "s/^/$(tput setaf "${colour}")[nginz] /" -e "s/$/$(tput sgr0)/" & else prefix=$([ -w /usr/local ] && echo /usr/local || echo "${HOME}/.wire-dev") - (cd ${SCRIPT_DIR} && LD_LIBRARY_PATH=$LD_LIBRARY_PATH:${prefix}/lib/ ${DIR}/../dist/nginx -p ${SCRIPT_DIR} -c ${SCRIPT_DIR}/conf/nginz/nginx.conf -g 'daemon off;' || kill_all) \ - | sed -e "s/^/$(tput setaf ${colour})[nginz] /" -e "s/$/$(tput sgr0)/" & + # shellcheck disable=SC2015 + (cd "${SCRIPT_DIR}" && LD_LIBRARY_PATH=$LD_LIBRARY_PATH:${prefix}/lib/ "${DIR}/../dist/nginx" -p "${SCRIPT_DIR}" -c "${SCRIPT_DIR}/conf/nginz/nginx.conf" -g 'daemon off;' || kill_all) \ + | sed -e "s/^/$(tput setaf "${colour}")[nginz] /" -e "s/$/$(tput sgr0)/" & fi } diff --git a/deploy/services-demo/register_idp_internal.sh b/deploy/services-demo/register_idp_internal.sh index 8a142efbad..c5bd491ac9 100755 --- a/deploy/services-demo/register_idp_internal.sh +++ b/deploy/services-demo/register_idp_internal.sh @@ -14,7 +14,7 @@ if [ ! -e "${metadata_file}" ]; then fi z_user=$2 -if [ ! -n "${z_user}" ]; then +if [ -z "${z_user}" ]; then echo "*** no z_user uuid" exit 80 fi diff --git a/dev-packages.nix b/dev-packages.nix index 8526417f04..c6cfbdfd66 100644 --- a/dev-packages.nix +++ b/dev-packages.nix @@ -180,6 +180,7 @@ in pkgs.jq pkgs.niv pkgs.ormolu + pkgs.shellcheck pkgs.wget pkgs.yq pkgs.rsync diff --git a/docs/legacy/developer/linting.md b/docs/legacy/developer/linting.md index 5dcbf75ab0..1861dd1fa4 100644 --- a/docs/legacy/developer/linting.md +++ b/docs/legacy/developer/linting.md @@ -1,6 +1,6 @@ # Linting -# HLint +## HLint To run [HLint](https://github.com/ndmitchell/hlint) you need it's binary, e.g. by executing: @@ -21,7 +21,7 @@ To run it on a sub-project: hlint services/federator ``` -# Stan +## Stan To run [Stan](https://github.com/kowainik/stan), you need it's binary compiled by the same GHC version as used in the project. @@ -53,3 +53,11 @@ To analyze a sub-project with stan: cd services/cargohold stan ``` + +## ShellCheck + +To lint shell scripts run [*ShellCheck*](https://github.com/koalaman/shellcheck): + +```sh +make shellcheck +``` diff --git a/hack/bin/cabal-install-artefacts.sh b/hack/bin/cabal-install-artefacts.sh index 9c83e763aa..caa74a97f7 100755 --- a/hack/bin/cabal-install-artefacts.sh +++ b/hack/bin/cabal-install-artefacts.sh @@ -19,4 +19,4 @@ cd "$TOP_LEVEL" cabal-plan list-bins "$pattern:exe:*" | awk '{print $2}' | xargs -i sh -c 'test -f {} && echo {} || true' | - xargs -P8 -i rsync -a {} "$DIST" + xargs -P8 -I{} rsync -a {} "$DIST" diff --git a/hack/bin/cabal-run-tests.sh b/hack/bin/cabal-run-tests.sh index 46a9099eca..c2ea19287e 100755 --- a/hack/bin/cabal-run-tests.sh +++ b/hack/bin/cabal-run-tests.sh @@ -14,8 +14,8 @@ fi for cabal in $(find "$TOP_LEVEL" -name "$pattern" | grep -v dist-newstyle); do # This is required because some tests (e.g. golden tests) must be run from # the package root. - cd "$(dirname $cabal)" - package="$(basename ${cabal%.*})" + cd "$(dirname "$cabal")" + package="$(basename "${cabal%.*}")" for test_suite in $(cabal-plan list-bins "$package:test:*" | awk '{print $2}'); do $test_suite "${@:2}" done diff --git a/hack/bin/copy-charts.sh b/hack/bin/copy-charts.sh index b0dfb3bff3..36b2ebd4a1 100755 --- a/hack/bin/copy-charts.sh +++ b/hack/bin/copy-charts.sh @@ -14,14 +14,14 @@ CHART_DIST=$TOP_LEVEL/.local/charts # TODO sanity check folder must exist mkdir -p .local/charts -rm -rf "$CHART_DIST/$CHART" +rm -rf "${CHART_DIST:?}/$CHART" cp -r "$CHART_SOURCE/$CHART" "$CHART_DIST/" if [ -f "$CHART_SOURCE/$CHART/requirements.yaml" ]; then # very hacky bash, I'm sorry for subpath in $(grep "file://" "$CHART_SOURCE/$CHART/requirements.yaml" | awk '{ print $2 }' | xargs -n 1 | cut -c 8-) do - rm -rf "$CHART_DIST/$CHART/$subpath" + rm -rf "${CHART_DIST:?}/$CHART/$subpath" cp -r "$CHART_SOURCE/$CHART/$subpath" "$CHART_DIST/" done fi diff --git a/hack/bin/diff-failure.sh b/hack/bin/diff-failure.sh index 44ce5946aa..ee7f3c9c16 100755 --- a/hack/bin/diff-failure.sh +++ b/hack/bin/diff-failure.sh @@ -1,4 +1,6 @@ #!/bin/bash + +# shellcheck disable=SC2162 sed 's| =/= |\n|' | { IFS= read first IFS= read second diff --git a/hack/bin/helm-template.sh b/hack/bin/helm-template.sh index d72684ce9b..03e88d5abe 100755 --- a/hack/bin/helm-template.sh +++ b/hack/bin/helm-template.sh @@ -25,4 +25,4 @@ if [ -f "$certificatesfile" ]; then fi "$DIR/update.sh" "$CHARTS_DIR/$chart" -helm template $"chart" "$CHARTS_DIR/$chart" ${options[*]} +helm template "$chart" "$CHARTS_DIR/$chart" "${options[*]}" diff --git a/hack/bin/integration-setup-federation.sh b/hack/bin/integration-setup-federation.sh index 7795226bab..fc4d927b21 100755 --- a/hack/bin/integration-setup-federation.sh +++ b/hack/bin/integration-setup-federation.sh @@ -8,8 +8,9 @@ export NAMESPACE=${NAMESPACE:-test-integration} HELMFILE_ENV=${HELMFILE_ENV:-default} CHARTS_DIR="${TOP_LEVEL}/.local/charts" +# shellcheck disable=SC1091 . "$DIR/helm_overrides.sh" -${DIR}/integration-cleanup.sh +"${DIR}/integration-cleanup.sh" # FUTUREWORK explore: have helmfile do the interpolation (and skip the "make charts" step) https://wearezeta.atlassian.net/browse/SQPIT-722 # diff --git a/hack/bin/integration-setup.sh b/hack/bin/integration-setup.sh index 634cc3a49f..d5f9d07111 100755 --- a/hack/bin/integration-setup.sh +++ b/hack/bin/integration-setup.sh @@ -8,6 +8,7 @@ export NAMESPACE=${NAMESPACE:-test-integration} HELMFILE_ENV=${HELMFILE_ENV:-default} CHARTS_DIR="${TOP_LEVEL}/.local/charts" +# shellcheck disable=SC1091 . "$DIR/helm_overrides.sh" "${DIR}/integration-cleanup.sh" diff --git a/hack/bin/integration-spring-cleaning.sh b/hack/bin/integration-spring-cleaning.sh index cf4451c134..95012ae966 100755 --- a/hack/bin/integration-spring-cleaning.sh +++ b/hack/bin/integration-spring-cleaning.sh @@ -1,7 +1,5 @@ #!/usr/bin/env bash -DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )/.." - set -x IFS=$'\n' diff --git a/hack/bin/integration-teardown-federation.sh b/hack/bin/integration-teardown-federation.sh index 76633f3c6a..030c58d8ca 100755 --- a/hack/bin/integration-teardown-federation.sh +++ b/hack/bin/integration-teardown-federation.sh @@ -12,5 +12,6 @@ export NAMESPACE_2="$NAMESPACE-fed2" export FEDERATION_DOMAIN_1="." export FEDERATION_DOMAIN_2="." +# shellcheck disable=SC1091 . "$DIR/helm_overrides.sh" helmfile --file "${TOP_LEVEL}/hack/helmfile.yaml" destroy diff --git a/hack/bin/integration-teardown.sh b/hack/bin/integration-teardown.sh index cd82194c2b..e06cbbc21e 100755 --- a/hack/bin/integration-teardown.sh +++ b/hack/bin/integration-teardown.sh @@ -9,5 +9,6 @@ export FEDERATION_DOMAIN="." set -ex +# shellcheck disable=SC1091 . "$DIR/helm_overrides.sh" helmfile --file "${TOP_LEVEL}/hack/helmfile-single.yaml" destroy diff --git a/hack/bin/integration-test-logs.sh b/hack/bin/integration-test-logs.sh index 8ba7dcd44e..99cad236a7 100755 --- a/hack/bin/integration-test-logs.sh +++ b/hack/bin/integration-test-logs.sh @@ -6,6 +6,7 @@ if [[ -z "$NAMESPACE" ]]; then exit 1 fi +# shellcheck disable=SC2162 while IFS= read LINE; do if [[ "$LINE" =~ ^Pod\ (.*)\ running$ ]]; then kubectl -n "$NAMESPACE" logs "${BASH_REMATCH[1]}" -f diff --git a/hack/bin/serve-charts.sh b/hack/bin/serve-charts.sh index edbb443877..48679bd5b9 100755 --- a/hack/bin/serve-charts.sh +++ b/hack/bin/serve-charts.sh @@ -2,14 +2,14 @@ set -euo pipefail -: ${HELM_SERVER_PORT:=4001} +: "${HELM_SERVER_PORT:=4001}" # get rid of all helm repositories # We need to deal with helm repo list failing because of https://github.com/helm/helm/issues/10028 (helm repo list -o json || echo '[]') | jq -r '.[] | .name' | xargs -I% helm repo remove % -cd "$(dirname "$BASH_SOURCE[0]")/../../.local/charts" -for chart in $@; do +cd "$(dirname "${BASH_SOURCE[0]}")/../../.local/charts" +for chart in "$@"; do ../../hack/bin/update.sh "$chart" helm package "$chart" done diff --git a/hack/bin/set-chart-image-version.sh b/hack/bin/set-chart-image-version.sh index 966a96c7c9..85dc294e4d 100755 --- a/hack/bin/set-chart-image-version.sh +++ b/hack/bin/set-chart-image-version.sh @@ -2,6 +2,7 @@ USAGE="$0 ..." docker_tag=${1?$USAGE} +# shellcheck disable=SC2124 charts=${@:2} TOP_LEVEL="$( cd "$( dirname "${BASH_SOURCE[0]}" )/../.." && pwd )" diff --git a/hack/bin/set-helm-chart-version.sh b/hack/bin/set-helm-chart-version.sh index 759da9a218..57abc500ee 100755 --- a/hack/bin/set-helm-chart-version.sh +++ b/hack/bin/set-helm-chart-version.sh @@ -24,6 +24,7 @@ function write_versions() { # update all dependencies, if any if [ -a requirements.yaml ]; then sed -e "s/ version: \".*\"/ version: \"$target_version\"/g" requirements.yaml > "$tempfile" && mv "$tempfile" requirements.yaml + # shellcheck disable=SC2207 deps=( $(helm dependency list | grep -v NAME | awk '{print $1}') ) for dep in "${deps[@]}"; do if [ -d "$CHARTS_DIR/$dep" ] && [ "$chart" != "$dep" ]; then diff --git a/hack/bin/upload-helm-charts-s3.sh b/hack/bin/upload-helm-charts-s3.sh index ae948633e1..010b13064c 100755 --- a/hack/bin/upload-helm-charts-s3.sh +++ b/hack/bin/upload-helm-charts-s3.sh @@ -95,11 +95,11 @@ cd "$TOP_LEVEL_DIR" # If ./upload-helm-charts-s3.sh is run with a parameter, only synchronize one chart if [ -n "$chart_dir" ] && [ -d "$chart_dir" ]; then - chart_name=$(basename $chart_dir) + chart_name=$(basename "$chart_dir") echo "only syncing $chart_name" charts=( "$chart_name" ) else - charts=( $(make -s -C "$TOP_LEVEL_DIR" echo-release-charts) ) + IFS=" " read -r -a charts <<< "$(make -s -C "$TOP_LEVEL_DIR" echo-release-charts)" # See Makefile/ CHARTS_RELEASE FUTUREWORK #charts=( $(find $CHART_DIR/ -maxdepth 1 -type d | sed -n "s=$CHART_DIR/\(.\+\)=\1 =p") ) fi @@ -161,7 +161,7 @@ if [[ "$reindex" == "1" ]]; then else # update local cache with newly pushed charts helm repo update - printf "\n--> Not reindexing by default. Pass the --reindex flag in case the index.yaml is incomplete. See all wire charts using \n helm search repo $REPO_NAME/ -l\n\n" + printf "\n--> Not reindexing by default. Pass the --reindex flag in case the index.yaml is incomplete. See all wire charts using \n helm search repo %s/ -l\n\n" "$REPO_NAME" fi diff --git a/libs/wire-api/test/golden/gentests.sh b/libs/wire-api/test/golden/gentests.sh index cff8c340c8..9a65e89dda 100644 --- a/libs/wire-api/test/golden/gentests.sh +++ b/libs/wire-api/test/golden/gentests.sh @@ -11,7 +11,8 @@ set -e set -o pipefail -export GOLDEN_TMPDIR=$(mktemp -d) +GOLDEN_TMPDIR=$(mktemp -d) +export GOLDEN_TMPDIR export GOLDEN_TESTDIR="test/unit/Test/Wire/API/Golden/Generated" # trap cleanup EXIT @@ -148,6 +149,7 @@ rm -fr "$GOLDEN_TESTDIR.hs" mkdir -p "$GOLDEN_TESTDIR" mkdir -p "$GOLDEN_TMPDIR/dump" +# shellcheck disable=SC2162 stack build --fast --test --bench --no-run-benchmarks wire-api | while read module section; do echo -ne "\033[KProcessing module $module...\r" @@ -194,10 +196,10 @@ for module in "$GOLDEN_TESTDIR"/*; do -e '/^import/d' \ -e "/^module/ r $dump" \ "$module" - ormolu -m inplace -c ${EXTS[@]/#/'-o '} "$module" + ormolu -m inplace -c "${EXTS[@]/#/'-o '}" "$module" done -ormolu -m inplace -c ${EXTS[@]/#/'-o '} "$GOLDEN_TESTDIR.hs" +ormolu -m inplace -c "${EXTS[@]/#/'-o '}" "$GOLDEN_TESTDIR.hs" ( cd ../.. && headroom run -a -s libs/wire-api/test/unit/Test/Wire/API/Golden/ ) # build one final time diff --git a/services/brig/federation-tests.sh b/services/brig/federation-tests.sh index 76acd31691..8e505d63a6 100755 --- a/services/brig/federation-tests.sh +++ b/services/brig/federation-tests.sh @@ -36,5 +36,5 @@ while read -r ip; do alsoProxyOptions+=("--also-proxy=${ip}") done < <(kubectl get pods -n "$NAMESPACE" -l wireService=cannon -o json | jq -r '.items[].status.podIPs[].ip') -# shellcheck disable=SC2086 +# shellcheck disable=SC2048,SC2086 telepresence --namespace "$NAMESPACE" --also-proxy=cassandra-ephemeral ${alsoProxyOptions[*]} --run bash -c "export INTEGRATION_FEDERATION_TESTS=1; ./dist/brig-integration -p federation-end2end-user -i i.yaml -s b.yaml" diff --git a/services/integration.sh b/services/integration.sh index 7a428fc83c..c42fbe415e 100755 --- a/services/integration.sh +++ b/services/integration.sh @@ -28,6 +28,8 @@ function list_descendants () { function kill_gracefully() { pkill "gundeck|brig|galley|cargohold|cannon|spar|nginz" sleep 1 + + # shellcheck disable=SC2046 kill $(list_descendants "$PARENT_PID") &> /dev/null } @@ -97,13 +99,15 @@ function run() { echo -e "\n\nWARNING: log output is buffered and may not show on your screen!\n\n" UNBUFFERED='' fi + # shellcheck disable=SC2086 ( ( cd "${DIR}/${service}" && "${TOP_LEVEL}/dist/${service}" -c "${configfile}" ) || kill_all) \ - | sed ${UNBUFFERED} -e "s/^/$(tput setaf ${colour})[${service}] /" -e "s/$/$(tput sgr0)/" & + | sed "${UNBUFFERED}" -e "s/^/$(tput setaf ${colour})[${service}] /" -e "s/$/$(tput sgr0)/" & } if [[ $INTEGRATION_CARGOHOLD_ONLY_COMPAT -eq 1 ]]; then - source "${CARGOHOLD_COMPAT_CONFIG_FOLDER}/env.sh" + # shellcheck disable=SC1091 + source "${CARGOHOLD_COMPAT_CONFIG_FOLDER}"/env.sh echo run cargohold "" ${purpleish} "${CARGOHOLD_COMPAT_CONFIG_FOLDER}/cargohold.integration.yaml" run cargohold "" ${purpleish} "${CARGOHOLD_COMPAT_CONFIG_FOLDER}/cargohold.integration.yaml" else @@ -125,12 +129,14 @@ function run_nginz() { # For nix we don't need LD_LIBRARY_PATH; we link against libzauth directly. # nix-build will put a symlink to ./result with the nginx artifact nginz=$(nix-build "${TOP_LEVEL}/nix" -A nginz --no-out-link ) - (cd ${NGINZ_WORK_DIR} && ${nginz}/bin/nginx -p ${NGINZ_WORK_DIR} -c ${NGINZ_WORK_DIR}/conf/nginz/nginx.conf -g 'daemon off;' || kill_all) \ + # shellcheck disable=SC2015,SC2086 + (cd "${NGINZ_WORK_DIR}" && "${nginz}"/bin/nginx -p "${NGINZ_WORK_DIR}" -c "${NGINZ_WORK_DIR}"/conf/nginz/nginx.conf -g 'daemon off;' || kill_all) \ | sed -e "s/^/$(tput setaf ${colour})[nginz] /" -e "s/$/$(tput sgr0)/" & else prefix=$([ -w /usr/local ] && echo /usr/local || echo "${HOME}/.wire-dev") - (cd ${NGINZ_WORK_DIR} && LD_LIBRARY_PATH=$LD_LIBRARY_PATH:${prefix}/lib/ ${TOP_LEVEL}/dist/nginx -p ${NGINZ_WORK_DIR} -c ${NGINZ_WORK_DIR}/conf/nginz/nginx.conf -g 'daemon off;' || kill_all) \ + # shellcheck disable=SC2015,SC2086 + (cd "${NGINZ_WORK_DIR}" && LD_LIBRARY_PATH=$LD_LIBRARY_PATH:${prefix}/lib/ "${TOP_LEVEL}"/dist/nginx -p "${NGINZ_WORK_DIR}" -c "${NGINZ_WORK_DIR}"/conf/nginz/nginx.conf -g 'daemon off;' || kill_all) \ | sed -e "s/^/$(tput setaf ${colour})[nginz] /" -e "s/$/$(tput sgr0)/" & fi } @@ -166,4 +172,5 @@ echo "all services are up!" ( ${EXE} "${@:2}" && echo 0 > "${EXIT_STATUS_LOCATION}" && kill_gracefully ) || kill_gracefully & wait +# shellcheck disable=SC2046 exit $(<"${EXIT_STATUS_LOCATION}") diff --git a/services/nginz/nginz_reload.sh b/services/nginz/nginz_reload.sh index f2ec41663e..aa5cef6d7e 100755 --- a/services/nginz/nginz_reload.sh +++ b/services/nginz/nginz_reload.sh @@ -12,13 +12,15 @@ watches=${WATCH_PATHS:-"/etc/wire/nginz/upstreams"} # only react on changes to upstreams.conf cfg=upstreams.conf +# shellcheck disable=SC2145 echo "Setting up watches for ${watches[@]}" { echo "nginx PID: $nginx_pid" + # shellcheck disable=SC2068,SC2162,SC2181 inotifywait -m -e moved_to -e modify,move,create,delete -m --format '%f' \ ${watches[@]} | while read file; do \ - if [ $file == $cfg ]; then \ + if [ "$file" == $cfg ]; then \ echo "Config file update detected"; \ nginx -t "$@"; \ if [ $? -ne 0 ]; then \ diff --git a/services/spar/test-scim-suite/mk_collection.sh b/services/spar/test-scim-suite/mk_collection.sh index 8e397c30e8..c7332a857a 100755 --- a/services/spar/test-scim-suite/mk_collection.sh +++ b/services/spar/test-scim-suite/mk_collection.sh @@ -3,9 +3,10 @@ set -e setup_js_jsonlines=$(mktemp /tmp/setup_inline_XXXXXXX.json) +# shellcheck disable=2002 cat ./setup.js | python3 -c ' import sys, json; print(json.dumps(sys.stdin.read().splitlines())) -' > $setup_js_jsonlines +' > "$setup_js_jsonlines" -jq --slurpfile setup_inline "$setup_js_jsonlines" -f ./update.jq $1 +jq --slurpfile setup_inline "$setup_js_jsonlines" -f ./update.jq "$1" diff --git a/services/spar/test-scim-suite/run.sh b/services/spar/test-scim-suite/run.sh index 6cca62596c..795e0f88f0 100755 --- a/services/spar/test-scim-suite/run.sh +++ b/services/spar/test-scim-suite/run.sh @@ -10,32 +10,36 @@ SCIM_TEST_SUITE_BRIG_PORT=8082 function create_team_and_scim_token { TOP_LEVEL="$( cd "$( dirname "${BASH_SOURCE[0]}" )/../../.." && pwd )" - IFS=',' read -r -a creds <<< $($TOP_LEVEL/deploy/services-demo/create_test_team_admins.sh -c) + IFS=',' read -r -a creds <<< "$("$TOP_LEVEL/deploy/services-demo/create_test_team_admins.sh" -c)" BRIG_HOST="http://$SCIM_TEST_SUITE_BRIG_HOST:$SCIM_TEST_SUITE_BRIG_PORT" WIRE_ADMIN_UUID=${creds[0]} WIRE_ADMIN=${creds[1]} WIRE_PASSWD=${creds[2]} - export BEARER=$(curl -X POST \ + BEARER=$(curl -X POST \ --header 'Content-Type: application/json' \ --header 'Accept: application/json' \ -d '{"email":"'"$WIRE_ADMIN"'","password":"'"$WIRE_PASSWD"'"}' \ $BRIG_HOST/login'?persist=false' | jq -r .access_token) + export BEARER SPAR_HOST="http://$SCIM_TEST_SUITE_SPAR_HOST:$SCIM_TEST_SUITE_SPAR_PORT" - export SCIM_TOKEN_FULL=$(curl -X POST \ + SCIM_TOKEN_FULL=$(curl -X POST \ --header "Authorization: Bearer $BEARER" \ --header 'Content-Type: application/json;charset=utf-8' \ --header 'Z-User: '"$WIRE_ADMIN_UUID" \ - -d '{ "description": "test '"`date`"'", "password": "'"$WIRE_PASSWD"'" }' \ + -d '{ "description": "test '"$(date)"'", "password": "'"$WIRE_PASSWD"'" }' \ $SPAR_HOST/scim/auth-tokens) + export SCIM_TOKEN_FULL - export SCIM_TOKEN=$(echo $SCIM_TOKEN_FULL | jq -r .token) - export SCIM_TOKEN_ID=$(echo $SCIM_TOKEN_FULL | jq -r .info.id) + SCIM_TOKEN=$(echo "$SCIM_TOKEN_FULL" | jq -r .token) + export SCIM_TOKEN + SCIM_TOKEN_ID=$(echo "$SCIM_TOKEN_FULL" | jq -r .info.id) + export SCIM_TOKEN_ID - echo $SCIM_TOKEN + echo "$SCIM_TOKEN" } function create_env_file { diff --git a/services/spar/test-scim-suite/runsuite.sh b/services/spar/test-scim-suite/runsuite.sh index 5166170424..204685eb26 100755 --- a/services/spar/test-scim-suite/runsuite.sh +++ b/services/spar/test-scim-suite/runsuite.sh @@ -1,5 +1,6 @@ #!/usr/bin/env nix-shell #!nix-shell shell.nix -i bash +#shellcheck shell=bash set -e @@ -9,5 +10,5 @@ if [[ "$INTEGRATION_SKIP_SCIM_SUITE" -eq 1 ]]; then exit 0 fi -make collection -C $SOURCE_DIR -$SOURCE_DIR/run.sh +make collection -C "$SOURCE_DIR" +"$SOURCE_DIR/run.sh" diff --git a/tools/db/move-team/dump_merge_teams.sh b/tools/db/move-team/dump_merge_teams.sh index 28be2ef437..7a5e9c9f5b 100644 --- a/tools/db/move-team/dump_merge_teams.sh +++ b/tools/db/move-team/dump_merge_teams.sh @@ -11,7 +11,7 @@ script=$( done ) -for f in $dir/*; do - echo $f - sed -e "$script" -i $f +for f in "$dir"/*; do + echo "$f" + sed -e "$script" -i "$f" done diff --git a/tools/nginz_disco/nginz_disco.sh b/tools/nginz_disco/nginz_disco.sh index 44b96e192c..2d8a7eb89f 100755 --- a/tools/nginz_disco/nginz_disco.sh +++ b/tools/nginz_disco/nginz_disco.sh @@ -19,6 +19,7 @@ function valid_ipv4() { if [[ $ip =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then OIFS=$IFS IFS='.' + # shellcheck disable=SC2206 ip=($ip) IFS=$OIFS [[ ${ip[0]} -le 255 && ${ip[1]} -le 255 \ @@ -40,16 +41,21 @@ function valid_ipv6() { function upstream() { name=$1 port=${2:-'8080'} + # shellcheck disable=2086 ips=$(dig +short +retries=3 +search ${name} | sort) unset servers + # shellcheck disable=SC2068 for ip in ${ips[@]}; do - if valid_ipv4 $ip || valid_ipv6 $ip; then + if valid_ipv4 "$ip" || valid_ipv6 "$ip"; then servers+=("\n\t server ${ip}:${port} max_fails=3 weight=100;") fi done; + # shellcheck disable=SC2128 if [ -n "$servers" ]; then + # shellcheck disable=SC2059,SC2116,SC2068 printf "upstream ${name} { \n\t least_conn; \n\t keepalive 32; $(echo ${servers[@]}) \n}\n" >> ${new} else + # shellcheck disable=SC2059 printf "upstream ${name} { \n\t least_conn; \n\t keepalive 32; \n\t server localhost:${port} down;\n}\n" >> ${new} fi } @@ -58,7 +64,7 @@ function routing_disco() { ivl=$(echo | awk '{ srand(); printf("%f", 1.5 + rand() * 1.5) }') upstreams=$(cat "$upstream_list") - upstreams=( $upstreams ) + upstreams=( "$upstreams" ) [[ -f $old ]] || touch -d "1970-01-01" $old @@ -74,8 +80,8 @@ function routing_disco() { rm -f $new - echo done, sleeping $ivl - sleep $ivl + echo done, sleeping "$ivl" + sleep "$ivl" } while true; do diff --git a/tools/ormolu.sh b/tools/ormolu.sh index e34fddf301..a364278716 100755 --- a/tools/ormolu.sh +++ b/tools/ormolu.sh @@ -38,6 +38,11 @@ while getopts ":fch" opt; do h ) echo "$USAGE" 1>&2 exit 0 ;; + * ) echo "Invalid option: $opt" + echo "$USAGE" 1>&2 + exit 1 + ;; + esac done shift $((OPTIND -1)) @@ -59,12 +64,13 @@ fi readarray -t EXTS < <(sed -n '/^default-extensions:/,$ { s/^- //p }' < package-defaults.yaml) echo "ormolu mode: $ARG_ORMOLU_MODE" +# shellcheck disable=SC2145 echo "language extensions: ${EXTS[@]}" FAILURES=0 if [ -t 1 ]; then - : ${ORMOLU_CONDENSE_OUTPUT:=1} + : "${ORMOLU_CONDENSE_OUTPUT:=1}" fi # https://github.com/tweag/ormolu/issues/38 @@ -73,9 +79,8 @@ export LANG=C.UTF-8 export LC_ALL=C.UTF-8 for hsfile in $(git ls-files | grep '\.hsc\?$'); do - FAILED=0 - # run in background so that we can detect Ctrl-C properly + # shellcheck disable=2068 ormolu --mode $ARG_ORMOLU_MODE --check-idempotence ${EXTS[@]/#/'-o -X'} "$hsfile" & wait $! && err=0 || err=$? diff --git a/tools/rebase-onto-formatter.sh b/tools/rebase-onto-formatter.sh index 1196fad8a3..84f908d91d 100755 --- a/tools/rebase-onto-formatter.sh +++ b/tools/rebase-onto-formatter.sh @@ -99,7 +99,7 @@ echo "Running the script now. This might take a while..." set -x # edit every commit Ci, adding new commits representing f at Ci and it's inverse g -git rebase $BASE_COMMIT~1 --exec "$FORMATTING_COMMAND && git commit -am format && git revert HEAD --no-edit" +git rebase "$BASE_COMMIT~1" --exec "$FORMATTING_COMMAND && git commit -am format && git revert HEAD --no-edit" # drop last commit (do not revert formatting at the end of the branch) git reset HEAD~1 --hard @@ -110,14 +110,16 @@ git reset HEAD~1 --hard # Ci=$(git rev-parse HEAD~1); git reset --soft HEAD~3; git commit --reuse-message $Ci # We do an interactive rebase, but instead of editing the commit sequence manually, # we use sed for that, inserting an `exec` command after every 3 commits. +# +# shellcheck disable=SC2016 GIT_SEQUENCE_EDITOR='sed -i -e "4~3s/^\(pick \S* format\)$/\1\nexec Ci=\$(git rev-parse HEAD~1); git reset --soft HEAD~3; git commit --reuse-message \$Ci/"' \ - git rebase --interactive $BASE_COMMIT + git rebase --interactive "$BASE_COMMIT" # rebase onto TARGET_COMMIT. # Annoyingly, we still have this first "format" commit that should already be # part of the TARGET_COMMIT. So we drop it. GIT_SEQUENCE_EDITOR='sed -i "1s/pick/drop/"' \ - git rebase --interactive $BASE_COMMIT --onto $TARGET_COMMIT + git rebase --interactive "$BASE_COMMIT" --onto "$TARGET_COMMIT" echo "Done." echo "Please check that the history looks as it should and all expected commits are there." diff --git a/tools/sftd_disco/sftd_disco.sh b/tools/sftd_disco/sftd_disco.sh index 63a603df96..e66e4901e4 100755 --- a/tools/sftd_disco/sftd_disco.sh +++ b/tools/sftd_disco/sftd_disco.sh @@ -12,14 +12,14 @@ old="/etc/wire/sftd-disco/sft_servers_all.json" new="${old}.new" function valid_entry() { - local line=$1 # TODO sanity check that this is real dig output + # local line=$1 return 0 } function valid_url() { - local url=$1 - #TODO basic sanity check + # TODO basic sanity check + # local url=$1 return 0 } @@ -30,21 +30,23 @@ function valid_url() { # this file can then be served from nginx running besides sft function upstream() { name=$1 + # shellcheck disable=SC2034 port=${2:-'8585'} - entries=$(dig +short +retries=3 +search SRV ${name} | sort) + entries=$(dig +short +retries=3 +search SRV "${name}" | sort) unset servers comma="" IFS=$'\n' - for entry in ${entries[@]}; do + for entry in "${entries[@]}"; do if valid_entry "$entry"; then sft_host_port=$(echo "$entry" | awk '{print $4":"$3}') - sft_url=$(curl -s http://$sft_host_port/sft/url | xargs) + sft_url=$(curl -s http://"$sft_host_port"/sft/url | xargs) if valid_url "$sft_url"; then - servers+=(${comma}'"'${sft_url}'"') + servers+=("${comma}"'"'"${sft_url}"'"') comma="," fi fi done + # shellcheck disable=SC2128,SC2145,SC2068 if [ -n "$servers" ]; then echo '{"sft_servers_all": ['${servers[@]}']}' | jq >${new} else @@ -68,10 +70,10 @@ function routing_disco() { rm -f $new - echo done, sleeping $ivl - sleep $ivl + echo done, sleeping "$ivl" + sleep "$ivl" } while true; do - routing_disco $srv_name + routing_disco "$srv_name" done