What I'd like to do is take, as an input to a function, a line that may include quotes (single or double) and echo that line exactly as it was provided to the function. For instance:
function doit { printf "%s " ${@} eval "${@}" printf " # [%3d]\n" ${?} }
Which, given the following input
doit VAR=42 doit echo 'single quote $VAR' doit echo "double quote $VAR"
Yields the following:
VAR=42 # [ 0] echo single quote $VAR # [ 0] echo double quote 42 # [ 0]
So the semantics of the variable expansion are preserved as I'd expect, but I can not get the exact format of the line as it was provided to the function. What I'd like is to have doit echo 'single quote $VAR'
result in echo 'single quote $VAR'
.
I'm sure this has to do with bash processing the arguments before they are passed to the function; I'm just looking for a way around that (if possible).
So what I had intended was to shadow the execution of a script while providing an exact replica of the execution that could be used as a diagnostic tool including exit status of each step.
While I can get the desired behavior described above by doing something like
while read line ; do doit ${line} done < ${INPUT}
That approach fails in the face of control structures (i.e. if
, while
, etc). I thought about using set -x
but that has it's limitations as well: "
becomes '
and exit status is not visible for commands that fail.
When you want to pass all the arguments to another script, or function, use "$@" (without escaping your quotes). See this answer: Difference between single and double quotes in Bash.
Normally, $ symbol is used in bash to represent any defined variable. But if you use escape in front of $ symbol then the meaning of $ will be ignored and it will print the variable name instead of the value. Run the following commands to show the effects of escape character (\).
bash [filename] runs the commands saved in a file. $@ refers to all of a shell script's command-line arguments. $1 , $2 , etc., refer to the first command-line argument, the second command-line argument, etc. Place variables in quotes if the values might have spaces in them.
$# is the number of positional parameters passed to the script, shell, or shell function. This is because, while a shell function is running, the positional parameters are temporarily replaced with the arguments to the function. This lets functions accept and use their own positional parameters.
I was in a similar position to you in that I needed a script to wrap around an existing command and pass arguments preserving quoting.
I came up with something that doesn't preserve the command line exactly as typed but does pass the arguments correctly and show you what they were.
Here's my script set up to shadow ls
:
CMD=ls PARAMS="" for PARAM in "$@" do PARAMS="${PARAMS} \"${PARAM}\"" done echo Running: ${CMD} ${PARAMS} bash -c "${CMD} ${PARAMS}" echo Exit Code: $?
And this is some sample output:
$ ./shadow.sh missing-file "not a file" Running: ls "missing-file" "not a file" ls: missing-file: No such file or directory ls: not a file: No such file or directory Exit Code: 1
So as you can see it adds quotes which weren't originally there but it does preserve arguments with spaces in which is what I needed.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With