0

I have these two functions in a bash script. I am just trying to pass arguments directly from one function to another without using global vars, but I can't seem to do it.

function suman {

  NODE_EXEC_ARGS= "--inspect"; 
  __handle_global_suman "${NODE_EXEC_ARGS}" "$@"

}


function __handle_global_suman {

  # I want $1 to be node exec args and $2 to be args to node script
  node $1 ${Z}/cli.js $2;

}

the problem I am having: in the __handle_global_suman function, the values for $1 and $2 seem to represent the original arguments passed to the suman function, not the arguments passed to __handle_global_suman! I want to be able to access the arguments pass to the __handle_global_suman function.

One solution is to use global variables like the following (but this is bad programming in general):

NODE_EXEC_ARGS="";  // default
ORIGINAL_ARGS="";  // default

function suman {

  NODE_EXEC_ARGS="--inspect";  
  ORIGINAL_ARGS="$@";  // assume this captures the arguments passed to this function, not the original script...
  __handle_global_suman
}

# ideally there would be a way to make this function truly private
function __handle_global_suman {

  # I want $1 to be node exec args and $2 to be args to node script
  node ${NODE_EXEC_ARGS} ${Z}/cli.js ${ORIGINAL_ARGS};

}

hopefully you see what I am trying to do and can help, thanks

4
  • Also, if there is a way to make the __handle_global_suman function truly private, that would be a nicety Commented Nov 25, 2016 at 23:47
  • 2
    You can't assign an array to a string without losing argument-boundary information. ORIGINAL_ARGS="$@" is thus inherently broken -- only an array, not a string, can store that value safely. See shellcheck.net for the more pedestrain quoting errors. Commented Nov 26, 2016 at 0:32
  • ...there's also a bunch of general-purpose bad practice here. The function keyword is needlessly incompatible with baseline POSIX sh shells (unlike most bash extensions, adding no value over the portable form, which is suman() { with no preceding function), and all-uppercase variable names are reserved by POSIX-specified convention for variables with meaning to the operating system or shell. Commented Nov 26, 2016 at 0:35
  • (rather, POSIX explicitly specifies that environment variables with meaning to tools it specifies are all-caps, and that all lower-case environment variables are reserved for application use -- but since setting a shell variable overwrites any like-named environment variable, the only way to be certain one isn't overwriting an environment variable with meaning to the system is to steer clear of the namespace). Commented Nov 26, 2016 at 0:37

3 Answers 3

2

In the below, we're passing an argument list stored in a local variable by reference:

suman() {
   local -a args=( --inspect --debug-brk )
   __handle_global_suman args "$@"
}

__handle_global_suman() {
   local ref="$1[@]"; shift
   node "${!ref}" "${Z}/cli.js" "$@"
}

Why is this different? Because we could also pass:

local -a args=( --inspect --argument-with-spaces="hello cruel world" )

...and it --argument-with-spaces=... would be passed correctly, as exactly one argument.

Sign up to request clarification or add additional context in comments.

16 Comments

huh, how does local get passed from suman to __handle_global_suman?
it would be neat if that local keyword worked for functions, then we could make a private function ?
Right. local is a keyword that makes your variables, well, local -- even if declared inside a function, all shell variables are global unless declare, typeset or local is used in their declaration.
it would be neat if that local keyword worked for functions, then we could make a private function ?
No, you can't make a private function, but... frankly, I'm not sure I see the point.
|
1

Your explanation is a little unclear, but I think I get the gist: word splitting isn't working as you expected in Bash.

You need to quote the ${NODE_EXEC_ARGS} parameter to you second function, since in the case that it is whitespace it will be stripped out and wont form a parameter to the called function:

__handle_global_suman "${NODE_EXEC_ARGS}" ${ORIGINAL_ARGS}

Also the ${ORIGINAL_ARGS} var is redundant in your example. You should just pass "$@" directly:

__handle_global_suman "${NODE_EXEC_ARGS}" "$@"

The second proposed alternative solution definitely isn't necessary, definitely is bad practice and you can definitely achieve what you want with Bash function parameter passing.

11 Comments

so if I quote the arguments, then they will get passed properly to the __handle_global_suman function?
this is not really working for me, can you let me know what isn't clear in the original question? I am just trying to pass arguments directly from one function to another without using global vars
Well, I meant you could have stripped it back to isolate exactly the problem you having. Like what's a "suman" etc. But I get the general jist, your bumping up against a word splitting issue.
re: "You also want to probably not quote the $1 when you pass it to node since it multiple args:" Yes, I agree, I will edit the original question to fix that so it's not a distraction.
$ORIGINAL_ARGS is not just redundant, it's broken. "foo bar" "baz qux" won't be kept as two words when passed that way, nor will "*.txt" retain its quoting.
|
0

Here is what works for me, thanks to the help @S.Pinkus whose answer I upvoted since the information contained in the answer was all I needed to fix the problem. Note the below works, but that @CDhuffy's answer is in theory more generic and therefore better.

function suman {

   __handle_global_suman "--inspect --debug-brk" "$@"

}

function __handle_global_suman {

   # ${1} is "--inspect --debug-brk"
   # ${2} is whatever I passed to the suman function
   node ${1}  ${Z}/cli.js ${2};

}

bash is awesome ;) ...not

7 Comments

This code is buggy. If instead of --inspect --debug-brk you wanted to pass --foo="bar baz", it wouldn't work for the reasons described in BashFAQ #50.
I see, can you mention a fix?
Which specific version of bash? I'd be tempted to use namevars if you're targeting 4.4 or newer.
let me check, it says "sh-3.2$"
btw it definitely does not work if I just use quotes like so: node "${1}" ${X}/cli.js "${2}";
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.