1

I need the ability to back up and then later use (both to read and print and to pass to another command as arguments) all input args to a bash program, but can't figure it out. Here is my attempt:

back_up_all_input_args.sh:

#!/usr/bin/env bash

all_args1="$@"
all_args2="$(printf "%q " "$@")"

# Simulate parsing the input args here
# - see: https://stackoverflow.com/a/14203146/4561887
shift # remove 1st arg
shift # remove 2nd arg

echo "$@"
echo "$all_args1"
echo "$all_args2"

# Do another program call with all input args here
# rg "$all_args1"  # FAILS
# rg "$all_args2"  # FAILS

Sample run and output:

$ ./backup_all_input_args.sh arg1 "arg 2" "arg 3"
arg 3
arg1 arg 2 arg 3
arg1 arg\ 2 arg\ 3 

My first approach was to back up the arguments with all_args1="$@". This fails because I lose the quotes and get arg1 arg 2 arg 3. My 2nd approach was to back up the arguments with all_args2="$(printf "%q " "$@")". This fails because again, I lose the quotes, and it just so happens the first argument doesn't just need to be stuck together with the backslash like a file path, but rather, it is a regular expression argument, so it needs to remain truly unmodified. This, therefore, is not equal to the original input: arg1 arg\ 2 arg\ 3 .

References I've already studied to get this far

  1. How to keep quotes in Bash arguments?
  2. How can I preserve quotes in printing a bash script's arguments
  3. How do I parse command line arguments in Bash?

Bash demo

Update: this Q&A, now that I have an answer, contributed to these bash demos I just wrote:

  1. back_up_all_input_args.sh
  2. array_practice.sh
  3. ...and culminated in this rapid find-and-replace tool wrapper I wrote around Ripgrep.
Gabriel Staples
  • 36,492
  • 15
  • 194
  • 265

1 Answers1

5

Add parentheses and store them in an array. This will preserve each of the arguments as separate words and avoids all the backslash escaping complexities.

all_args=("$@")

You can then pass the arguments to another command:

cmd "${all_args[@]}"

Or print them out:

printf '[%s]\n' "${all_args[@]}"

Or assign them to another array:

args_copy=("${all_args[@]}")

You can also use set restore the script's original $1, $2, etc., arguments:

set -- "${all_args[@]}"
John Kugelman
  • 349,597
  • 67
  • 533
  • 578
  • Thank you. I credited you in this commit :) https://github.com/ElectricRCAircraftGuy/eRCaGuy_hello_world/commit/231c1cae164989530dfa55211698e23eb4c65d54 – Gabriel Staples Jan 04 '22 at 04:30
  • And [here is the culmination of what this was for: `rgr`](https://github.com/ElectricRCAircraftGuy/eRCaGuy_dotfiles/blob/master/useful_scripts/rg_replace.sh) (Ripgrep Replace--allows ripgrep to find and replace on your disk). It finally works! – Gabriel Staples Jan 04 '22 at 08:30
  • 1
    I've used and referenced this answer a lot since you gave it. It clarified a lot of things for me and allowed me to more-fully use bash arrays, which are extremely useful in so many cases. As a result of your answer, I've now been able to answer this as well, which I recently needed myself: [Passing arrays as parameters in bash](https://stackoverflow.com/a/70855715/4561887). Thanks again. – Gabriel Staples Jan 26 '22 at 00:34
  • 1
    I'm glad it helped you so much. It's nice to hear. Cheers! – John Kugelman Jan 26 '22 at 03:18