How to pass all arguments of a function along to another command?

6,949

Solution 1

Within your program shell function, use "$@" to refer to the list of all command line arguments given to the function. With the quotes, each command line argument given to program would additionally be individually quoted (you generally want this).

program () {
    "$GOBIN"/program "$@"
}

You would then call program like so:

program -p hello_world -tSu

or, if you want to pass hello world instead of hello_world,

program -p 'hello world' -tSu

Using $1 refers to only the first command line argument (and $2 would refer to the second, etc.), as you have noticed. The value of $1 would additionally be split on white-spaces and each generated string would undergo filename globbing, since the expansion is unquoted. This would make it impossible to correctly pass an argument that contains spaces or filename globbing patterns to the function.

Solution 2

"$@" is the way to provide pass all arguments received by a function / script, as answered by Kusalananda.

However, given that you seem to be using a folder with your go programs, I think you would be better served by simply adding your $GOBIN folder to your PATH:

export GOPATH="$HOME/go_projects"
export GOBIN="$GOPATH/bin"
export PATH="$PATH:$GOBIN"

This way you could run any program stored in $GOBIN just by typing its name (unless it has the same name of an existing program, we are appending $GOBIN to $PATH, so these programs would be picked last).

PS: For completeness, there is a third option which would be to use an alias instead of a function, you could place in .bashrc:

alias program="$GOBIN/program"
Share:
6,949

Related videos on Youtube

nooby
Author by

nooby

Updated on September 18, 2022

Comments

  • nooby
    nooby over 1 year

    Hello I have this in my ~/.bash_profile

    export GOPATH="$HOME/go_projects"
    export GOBIN="$GOPATH/bin"
    
    program(){
            $GOBIN/program $1
    }
    

    so I'm able to do program "-p hello_world -tSu". Is there any way to run the program and custom flags without using the quotation marks? if I do just program -p hello_world -tSu it'll only use the -p flag and everything after the space will be ignored.

    • Zorawar
      Zorawar over 3 years
      "...is there anyway to run the program and custom flags without using the quotation marks?" Yeah, install zsh! The reason why you should have quotes in bash and in some other shells is for historical reasons, which you can look up. Basically, bash will "split" variables whenever they are not quoted. Consider the following code: foo() { echo "1: $1"; echo "2: $2"; }; var="a b"; foo $var, whereby bash "splits" the string in var into two arguments to foo (namely, "a" and "b"). (Zsh does away with this legacy behaviour, so quotes are rarely needed.)
    • ilkkachu
      ilkkachu over 3 years
      @Zorawar, and how would Zsh and the fact that it does not split help here? If you did foo() { ls $1; } and foo "-l foo.txt" in Zsh, it wouldn't work exactly because of the lack of splitting, and foo -l foo.txt also wouldn't pass all the arguments along. Regardless of the shell, you still need $@ to pass all the arguments.
    • Zorawar
      Zorawar over 3 years
      @ilkkachu OP: "Is there any way to run the program and custom flags without using the quotation marks." My tongue-in-cheek answer was essentially, no, not unless you use a shell that does this. The reason why bash does not do this is because of word splitting, which I thought the OP would like to know in order to appreciate why this is so. Yes, zsh does not split on raw strings, but we are talking about the behaviour of parameters, not strings. I don't see why $@ joined the discussion, though.
    • ilkkachu
      ilkkachu over 3 years
      @Zorawar, the example was program "-p hello_world -tSu", which, when used with $GOBIN/program $1 runs $GOBIN/program -p hello_world -tSu, that is, $GOBIN/program gets three distinct arguments. To do the same without quotes, they'd do program -p hello_world -tSu, where the function program itself gets three arguments. $1 only contains one of them, in both Bash and Zsh. To pass all the arguments on, you have to use $@. (Or if you want to lock yourself to exactly three arguments, $1 to $3.) With Zsh you could use just $@, but with Bash, you need to quote it "$@".
    • Zorawar
      Zorawar over 3 years
      @ilkkachu I appreciate that, but I am not, and did not, address that. The answers below have covered that sufficiently well. I just added my comment as supplementary information about why quotes in general are very much recommended in bash, which was my reading between the lines of why the OP asked about quotation marks since, on the surface, why doesn't $1 include all the other arguments shows a certain lack of understanding of how and why quotes are needed in shell code.
    • ilkkachu
      ilkkachu over 3 years
      @Zorawar, I fail to see how $1 not including anything but the first argument has anything to do with quotes. Yes of course foo $var will split in Bash but not Zsh, but that's not what they were doing in the question. Yes, perhaps the issue here was that they didn't know what $1 is, or how to refer to the other arguments, but your comment did nothing to help that either. Really, I just hope people would write comments like that as answers so that they could be downvoted.
  • nooby
    nooby over 3 years
    Thanks this worked, though I don't know why you need quotations for the $GOBIN, confuses me a bit. but thats okay tyvm! will accept when I am able too
  • Kusalananda
    Kusalananda over 3 years
    @nooby In this particular case, you may not need quoting of $GOBIN, but you would definitely need it if it happened to contain spaces. See unix.stackexchange.com/questions/131766 and unix.stackexchange.com/questions/68694 In general, it's safest to always quote variable expansions, unless you know for sure that you don't need to (or you want to actually invoke splitting and globbing on the value of the variable).
  • nooby
    nooby over 3 years
    Thanks for adding an even more in depth expiation and answering my second question, much appreciated. i'll check those threads out, have a good day