Argument Display with ${*@Q} (Not for ReExecution)
"${*@Q}"
Safe Argument Display with ${*@Q}
What It Does
${*@Q}
safely quotes all arguments as a single string - perfect for logging what a function received.
Basic Usage
#!/bin/bash
foo() {
echo "Called with: ${*@Q}"
# Output: 'hello world' 'it'\''s working' 'test"quote'
}
foo "hello world" "it's working" 'test"quote'
Common Patterns
# Debug logging
debug() { echo "[DEBUG] ${FUNCNAME[1]}: ${*@Q}" >&2; }
# Command history
log_cmd() { echo "$(date): ${*@Q}" >> history.log; }
# Dry run display
dry_run() { echo "Would run: ${*@Q}"; }
⚠️ Important Limitation
${*@Q}
creates a single string - great for display, wrong for re-execution:
# WRONG - loses argument boundaries
saved="${*@Q}"
eval "cmd $saved" # Passes everything as ONE argument!
# RIGHT - use "$@" for execution
cmd "$@" # Preserves separate arguments
Key Points
- Works inside functions (unlike
${@Q}
) - Use for displaying arguments, not executing
- Handles spaces, quotes, and special characters safely
- Bash 4.4+ required
Snapshot to try out
GT-Sandbox-Snapshot
Code
foo() {
local -n some_local_name="${1:?name of external variable}"
some_local_name=42
}
bar() {
some_global_result=42
}
time_name_ref() {
local var1
for i in {1..10000} ; do
foo var1
done
}
time_result_pattern(){
local var1
for i in {1..10000} ; do
bar
var1="${some_global_result:?}"
done
}
main() {
# Warmup
for i in {1..100}; do
foo var1
bar
done
time time_name_ref
time time_result_pattern
}
main "${@}" || exit 1
Command to reproduce:
gt.sandbox.checkout.commit f3e5ad2656054f3e269d \
&& cd "${GT_SANDBOX_REPO}/bash" \
&& cmd.run.announce "./main.sh"
Recorded output of command:
real 0m0.038s
user 0m0.037s
sys 0m0.000s
real 0m0.025s
user 0m0.025s
sys 0m0.000s