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