0

So I am new learning bash script and I came up with the following piece of code.

run_command() {
  echo "+" "$@"
  "$@"
}

I am confused on what "$@" means and why is it twice?

Thanks a lot for your time and have a great day.

Cyrus
  • 84,225
  • 14
  • 89
  • 153

2 Answers2

2

This prints the command and its output.

e.g.

run_command() {
  echo "+" "$@"
  "$@"
}

run_command ls

#output
#+ ls
#files_list_in_current_directory
Aagam Jain
  • 1,546
  • 1
  • 10
  • 18
  • But how is "$@" doing that? I am confused on what "$@" is. – Jenny Smith Sep 23 '18 at 17:06
  • @JennySmith see this https://stackoverflow.com/questions/12314451/accessing-bash-command-line-args-vs. That'll lead you to learning about "$@" – zedfoxus Sep 23 '18 at 17:07
  • Oh Sorry. `$@` holds the arguments passed to your function. – Aagam Jain Sep 23 '18 at 17:07
  • @AagamJain so it holds the arguments and the output as well? – Jenny Smith Sep 23 '18 at 17:12
  • 1
    @JennySmith `$@` is just the arguments. `echo "+" "$@"` runs the `echo` command to print a "+" followed by the arguments, and then `"$@"` by itself runs the arguments themselves as a command (and just lets output go to the usual place). So if you ran `run_command cp file1 file2`, it would execute `echo + cp file1 file2` and then `cp file1 file2`. – Gordon Davisson Sep 23 '18 at 17:24
  • @GordonDavisson Thanks a lot for the explanation :D. I am just confused now on why "$@" acts in two different ways. For the first one it just acts like a string to let itself be echoed and for the second one, it actually executes the function with its parameters. Why is this? – Jenny Smith Sep 23 '18 at 17:45
  • @JennySmith great questions. This is the right answer, but for additional explanation beyond the comments I've added an answer that walks you through the process. – zedfoxus Sep 23 '18 at 17:48
2

Aagam Jain's got the answer. I will add some explanation that wouldn't fit in a comment section. I apologize for the verbosity.

Consider this example.

Showing parameters given to a script

test.sh:

echo "$1"
echo "$2"

Let's run this script and give it 2 parameters.

$> bash test.sh ls -l

Result:

ls
-l

First parameter ls, represented by $1, is echo'ed in the first line. Second parameter -l, represented by $2, is echo'ed in the second line.

Bash manual - let's see what it says

($@) Expands to the positional parameters, starting from one

See this: https://www.gnu.org/software/bash/manual/bash.html#Special-Parameters

How does that impact our example? Let's change test.sh a bit.

Expanding parameters starting from one

test.sh:

echo "$@"

Let's run it.

$> bash test.sh ls -l

Result:

ls -l

$@ listed both parameters in the same line one after the other. If you had 5 parameters, they'd be printed one after the other.

Let's change test.sh a bit more.

Adding a + to the echo

test.sh:

echo "+" "$@"

Let's run it.

$> bash test.sh ls -l

Result:

+ ls -l

That means, a + appeared before both parameters were printed.

Change test.sh a bit more.

Executing all provided parameters

test.sh:

echo "+" "@"
"$@"

Let's run this.

bash test.sh ls -l

Result:

+ ls -l
total 4
-rw-r--r-- 1 eapo users  0 Sep 23 19:38 file1
-rw-r--r-- 1 eapo users 19 Sep 23 19:38 test.sh

Great. As the commenters and Aagam mentioned, the script printed out what it was going to execute (using echo "+" "$@") and then executed the command. The "$@" basically is just doing ls -lh. Terminal just executes it as is.

Let's put a function in the script now.

Adding a function in the script

test.sh:

run_command() {
    echo "+" "$@"
    "$@"
}

run_command ls -l

Note that we are executing the function in the script itself instead of giving it on the command line

Let's run it.

bash test.sh

Result:

+ ls -l
total 4
-rw-r--r-- 1 eapo users  0 Sep 23 19:38 file1
-rw-r--r-- 1 eapo users 58 Sep 23 19:41 test.sh

Hope the examples walk you through how the script functions.

Benjamin W.
  • 46,058
  • 19
  • 106
  • 116
zedfoxus
  • 35,121
  • 5
  • 64
  • 63
  • Up Vote :). Awesome explanation. – Aagam Jain Sep 23 '18 at 17:51
  • Thanks for the great explanation! – Jenny Smith Sep 23 '18 at 17:58
  • Awesome. Good teamwork. @JennySmith although completely optional, you may want to give closure to your question by marking Aagam's answer as accepted and probably giving him an upvote also. – zedfoxus Sep 23 '18 at 18:06
  • @JennySmith you might want to accept Aagam's answer as accepted rather than mine. Aagam answered first and was an accurate answer. Mine just had additional explanation. – zedfoxus Sep 23 '18 at 18:43