12

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.

Kusalananda
  • 333,661
nooby
  • 131
  • 1
  • 1
  • 5
  • "...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.) – Zorawar Nov 24 '20 at 02:02
  • 2
    @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. – ilkkachu Nov 24 '20 at 08:48
  • @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. – Zorawar Nov 24 '20 at 15:51
  • @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. – Zorawar Nov 24 '20 at 17:38
  • This question seems to be quite different from the title. – Peter Kionga-Kamau Feb 21 '23 at 15:09

3 Answers3

30

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.

Kusalananda
  • 333,661
  • 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 – nooby Nov 23 '20 at 12:33
  • 1
    @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 https://unix.stackexchange.com/questions/131766 and https://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). – Kusalananda Nov 23 '20 at 12:37
  • 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 – nooby Nov 23 '20 at 12:40
  • if you save $@ in a variable first: ARGS="$@", do you need to quote the variable when you forward the args? program $ARGS or program "$ARGS" ? – minseong Feb 18 '24 at 08:12
  • 1
    @minseong First of all, you would save it in an array, not in a scalar variable, array=( "$@" ), and yes, you must quote it if you want to access it as a list, "${array[@]}" – Kusalananda Feb 18 '24 at 12:46
6

"$@" 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"
Ángel
  • 3,589
-1

What worked for me is the following:

m() {
    args="$@"
    usql mysql://root@localhost:3306 -c $args
}

This actually placed a quoted set of arguments at the end of my command, such that I can run commands like:

m show databases;

And it actually runs

usql mysql://root@localhost:3306 -c "show databases;"
  • 1
    What shell are you running? I would expect the behaviour that you describe from the zsh shell, but note that the question at hand is concerned with the bash shell. – Kusalananda May 03 '23 at 05:09