Reusable Bash functions are easier to maintain when they live in a separate file instead of being copied into every script. Sourcing that file loads the definitions into the current shell process, so the caller can use the functions as if they were written in the same script.
The source builtin, and the equivalent . form, read shell code in the current context. A sourced function file needs read permission, not execute permission. Source only project files you trust, because variables, functions, shell options, and directory changes made inside the file affect the caller after the source command finishes.
The example keeps deploy-label formatting in project-functions.sh and imports it from deploy-check.sh. Passing an argument to source lets the function file initialize a profile value before the caller runs the loaded function.
Related: How to create a function in Bash
Related: How to create and run a Bash script
PROJECT_PROFILE=${1:-default} deploy_label() { local service=$1 printf "%s-%s\n" "$PROJECT_PROFILE" "$service" }
The function file is intended to be sourced, so it does not need a shebang or execute permission.
#!/usr/bin/env bash set -euo pipefail source ./project-functions.sh payment deploy_label api deploy_label worker
The ./ prefix points to the function file in the current directory instead of relying on a name search. Keep that path explicit in scripts so the imported functions come from the intended project file.
$ bash -n project-functions.sh
No output means Bash did not find a parse error.
$ bash -n deploy-check.sh
No output means Bash parsed the caller script without finding a syntax error.
$ bash deploy-check.sh payment-api payment-worker
$ source ./project-functions.sh payment
The payment argument becomes $1 while the file is being sourced, so project-functions.sh sets PROJECT_PROFILE for that shell.
$ declare -F deploy_label deploy_label
$ deploy_label api payment-api