-1

So I have a set of scripts that have been working for a while. They do various things and pass the original command line parameters to one another using "$@". This was fine, until the day one parameter contained various dollar signs like dollar$aregreatexceptneed$inglequote$

Now this is easily fixable in a manual end command or the first script wrapping it in single quotes.

The problem I have is that when that gets passed through with "$@" it is then being double-quoted, which is causing issues as it tries to interpret non-existent variables and I end up with truncated values - which I have confirmed by adding debug outputs to each script, it's lost after the 1st pass-through with "$@".

Extra info: It can have a variable number of parameters(hence using "$@"). It can go through a variable number of scripts.

So essentially what i need is a way to pass them through, but with that parameter - wherever it may be, single-quoted each time. Tricky one to even google relevant results for.

Any advice appreciated.

Edit because of duplicate flag: So a bit more info, I'm not actually sure how it's confused with the duplicate - but to highlight the difference, the linked duplicate : How do I pass on script arguments that contain quotes/spaces? This is a different issue, as these scripts actually already incorporated those solutions, and have for years to deal with spaces and quoting. This question is specifically about the shortcomings of "$@".

But yes I am aware that this question isn't written in a great manner(I almost didn't post it because of it) but I really can't think how to better verbalize it due to it's nature, and thanks to those who have taken the time to help despite this.

Louis M.
  • 143
  • 13
  • instead of passing the arguments using `"$@"`, you can pass them using `"$1"`, `"$2"`, `"$3"` ! – Freeman Jun 27 '23 at 15:35
  • Hi, it is difficult for us to see what the issue is by your description. Would it be possible to provide us a minimal example where this would be failing? What you are describing seems very unlikely to happen in nominal usage, so it seems you are dealing with some additional code which would expand those "variables". – kvantour Jun 27 '23 at 15:37
  • 3
    Variables aren't expanded recursively. If a parameter contains dollar signs, they won't be processed when `"$@"` is expanded. So this shouldn't be a problem. – Barmar Jun 27 '23 at 15:38
  • Are you using `eval` anywhere in your script? That would cause a problem with these parameters. – Barmar Jun 27 '23 at 15:38
  • @Freeman The problem is I don't know how many there are. Hence "$@" in the first place. – Louis M. Jun 27 '23 at 15:40
  • @kvantour I will see what I can add, just need to strip loads of confidential stuff out o/c - and I didn't think it would add much. but one simple example really is just echo $(ssh $location "$@") where it receives a bunch of parameters, one of which is single quoted containing $. The ssh receiving one gets it mangled after the $ on a 1st line dump. – Louis M. Jun 27 '23 at 15:43
  • 3
    That SSH command would indeed be a problem, because the arguments get re-evaluated by the shell on the server. Passing variables through SSH is tricky. – Barmar Jun 27 '23 at 15:56
  • 1
    `ssh` _itself_ mangles things. It's not a local shell problem, it's a ssh problem; ssh basically takes `"$@"` and rewrites it into `"$*"`. Consider using `ssh remotehost "${*@Q}"` instead, assuming bash 5.0+ – Charles Duffy Jun 27 '23 at 16:06
  • 1
    You can also use `printf -v cmd_q '%q ' "$@"` and then `ssh remotehost "$cmd_q"` – Charles Duffy Jun 27 '23 at 16:11
  • 1
    (but that's wrong in every case where you _don't_ have something like ssh concatenating parameters into a single string and passing that string to a shell as code; it's a special-case solution for a special-case problem, not something to do habitually) – Charles Duffy Jun 27 '23 at 16:12
  • https://idownvotedbecau.se/nocode/ – user1934428 Jun 28 '23 at 06:42
  • @CharlesDuffy Interesting, after a closer look it is maybe possible that is is only ssh ones the issue - maybe. Should be easy to detect just them commands and substitute with this to find out. – Louis M. Jun 28 '23 at 07:57
  • @CharlesDuffy What is this ZSH-type of abomination (`${*@Q}`). Always nice to discover a new section in the bash-manual – kvantour Jun 28 '23 at 09:17
  • @CharlesDuffy so ssh remotehost "${*@Q}" does indeed work - although I will admit, I have no idea WHY. As I don't have a clue what the @Q part means :) – Louis M. Jun 28 '23 at 09:27
  • 1
    Search for "parameter transformation" in `man bash`. The entry for `Q` therein is as follows: _The expansion is a string that is the value of parameter quoted in a format that can be reused as input._ – Charles Duffy Jun 28 '23 at 12:26

2 Answers2

1

check this out :

#!/bin/bash
for arg in "$@"
do
  if [[ "$arg" == *\$* ]]; then
    arg=$(printf "%q" "$arg")
  fi
  args+=("$arg")
done

./next_script.sh "${args[@]}"
Freeman
  • 9,464
  • 7
  • 35
  • 58
  • this seems to make sense, will give it a try as soon as I get chance and report back! – Louis M. Jun 27 '23 at 15:49
  • This won't work if `$arg` contains single quotes. – Barmar Jun 27 '23 at 15:53
  • @Barmar Yes, you are right. I fixed it. I always learn something from you. Thank you for always being there and guiding us. – Freeman Jun 27 '23 at 16:06
  • You should use `%q` _or_ add single quotes. Doing both can end in a result that doesn't actually parse back to the original content. – Charles Duffy Jun 27 '23 at 16:16
  • @CharlesDuffy thnx for your tip – Freeman Jun 27 '23 at 17:20
  • BTW, usually when writing this kind of logic I'll generate a single string, not an array: the whole reason adding quotes is necessary is _because_ the original argument boundaries aren't being honored (in this case, by ssh); maintaining an array implies that those boundaries are still meaningful. Using `printf -v args_str '%q ' "$@"; ./next_script.sh "$args_str"` is explicit that we're losing the original array meanings and can _only_ evaluate items by parsing them back out again; being clear about that is generally better than not. – Charles Duffy Jun 27 '23 at 18:34
0

script1

#! /bin/bash

var=123
./script2 'this is' an example 'of $var' "and $var"

script2

#! /bin/bash

for a in "$@"; do
    echo $a
done

then

./script1
this is
an
example
of $var
and 123

so the problem you are trying to fix does not exist.

Diego Torres Milano
  • 65,697
  • 9
  • 111
  • 134
  • Saying the problem doesn't exist doesn't answer the question. Obviously they *are* having a problem, so there's something else going on. – Barmar Jun 27 '23 at 15:55