1

So, lets say I have 6 files that are all the same type. In my specific case all of them are zip files and I want to select all of them and "pass them through" a shell script that "unzips" all of them.

I can already do it selecting one by one as the script simply does:

#!/bin/bash
DIR=$(dirname "$@")
exec unzip "$@" -d "${DIR}"

So it unzips the "zip file" exactly where I have it.
Now, when I select multiple files (aka more than one file). I don't know what happens as I don't fully understand what is "parsed" into the script.
I found this What does $@ mean in a shell script?

So I would like to know how to do it right. Thanks a lot.

Charles Duffy
  • 280,126
  • 43
  • 390
  • 441
  • You're passing all your arguments to `dirname` at once -- so if you run `yourscript one two three`, it runs `DIR=$(dirname one two three)`, and `unzip one two three -d "$DIR"`. – Charles Duffy Dec 14 '17 at 22:06
  • BTW, this is not GitHub -- triple quotes don't create a code block here. Use four-space indents for multi-line blocks of code that should be syntax highlighted, as performed by the `{}` button in the editor when such a multi-line block is selected. – Charles Duffy Dec 14 '17 at 22:08
  • Hey Charles, the {} button didn't work for the multiline but thanks for the advice, it looked fine on the preview. – Francisco Laferrière Dec 15 '17 at 02:39
  • ...so, if you use backticks for a multi-line block, the grey background doesn't extend all the way across the line but only covers the place where the text is, and there's no syntax highlighting (which only shows up in the preview after a few seconds). It's subtle, but it *is* noticeable -- compare the current formatting to that in https://stackoverflow.com/revisions/47822660/1 – Charles Duffy Dec 15 '17 at 02:44
  • (btw, re: "the {} button didn't work" -- what exactly happened when you tried to use it? If it just inserted `enter code here` with backticks around it, that implies that there wasn't actually a multi-line block selected when it was clicked). – Charles Duffy Dec 15 '17 at 02:49
  • The button just made the "code" only the first line, the rest of them were ignored, I don't recall exactly. BUT I see your point on the other formatting, the box spans for the entire width of the text box. – Francisco Laferrière Dec 16 '17 at 05:43

2 Answers2

4

Fixing Your Script: Iterating Over Arguments

If you're calling commands (like unzip) that only take one argument (of the type you want to pass) at a time, then you need to iterate over them. That is:

#!/bin/bash
for arg in "$@"; do       # or just "for arg do"
  dir=$(dirname "$arg")
  unzip "$arg" -d "$dir"
done

Literal Answer (What The Original Syntax Did)

"$@" expands to the complete list of positional arguments. What does that mean in practice?

Let's say your code were called with:

./yourscript "Directory One/file1.zip" "Directory Two/file2.zip"

In this case, you would have:

# this is what your code would try to do (it's an error!)
DIR=$(dirname "Directory One/file1.zip" "Directory Two/file2.zip")

...followed by:

# also doesn't work, since "unzip" only takes a single zipfile argument
# ...and because the above dirname fails, DIR is empty here
unzip "Directory One/file1.zip" "Directory Two/file2.zip" -d "$DIR"
Charles Duffy
  • 280,126
  • 43
  • 390
  • 441
  • I knew I had to do some iteration but I was missing that "arg" part for the "$@", If I got it correctly arg will vary depending on the amount of "things" that @ has, right? So if I have 10 items selected, @ will have from 0 to 9 "values". Is that correct? BTW thanks for the code that works. :D – Francisco Laferrière Dec 15 '17 at 02:37
  • `for arg in ...` will run the loop as many times as there are items in `...`, assigning `arg` to each value in turn. So with `"$@"` (which is the same as `"$1" "$2" "$3"` etc. for as many arguments as the current script/function/etc. was given), it will first run the body (that is, everything between the `do` and the `done`) with `arg="$1"`, then a second time with `arg="$2"`, etc. – Charles Duffy Dec 15 '17 at 02:43
0

Quoting from the official manual:

@ - Expands to the positional parameters, starting from one. When the expansion occurs within double quotes, each parameter expands to a separate word. That is, "$@" is equivalent to "$1" "$2" .... If the double-quoted expansion occurs within a word, the expansion of the first parameter is joined with the beginning part of the original word, and the expansion of the last parameter is joined with the last part of the original word. When there are no positional parameters, "$@" and $@ expand to nothing (i.e., they are removed).

Charles Duffy
  • 280,126
  • 43
  • 390
  • 441
  • 3
    StackOverflow frowns on [plagiarized answers](https://meta.stackexchange.com/questions/160071/what-to-do-when-plagiarism-is-discovered). This answer is cut-and-paste from the bash man page. It would be good form to mark the text as a quote (prepend lines with `>`) and credit the man page. – John1024 Dec 14 '17 at 22:06
  • I've edited this to be a proper link to the upstream documentation. @sos, please do this yourself in the future. – Charles Duffy Dec 15 '17 at 21:51