7

I'm using bash as my main shell, but it's an open question and responses for shells others than bash are very welcome.

If I'm typing interactively

#original line 
#wget http://something.com && unzip something && mv -f something /home/poney/ 
#new line
wget http://something.com ; unzip something ; mv -f something /home/poney/

Does it make any difference in term of execution pile, order, memory, interpretation, permission compare to a script that contains those line:

#!/bin/bash
wget http://something.com
unzip something 
mv -f something /home/poney/

PS:

except the fact that executing a script is shorter than typing 3 command in a row obviously.

Braiam
  • 35,991
Kiwy
  • 9,534

3 Answers3

17

Yes, there is a big difference. && is short-circuiting, so the subsequent command would be executed only if the previous one returned with an exit code of 0.

Quoting from the manual:

expression1 && expression2

True if both expression1 and expression2 are true.

On the other hand, a script containing

expression1
expression2

would execute the second expression even if the first failed. (Unless you specified the script to exit on error by saying set -e.)


EDIT: Regarding your comment whether:

command1; command2

is the same as:

command1
command2

The answer is usually. Bash parses an entire statement block before evaluating any of it. A ; doesn't cause the previous command to be evaluated. If the previous command were to have an effect on how the subsequent one would be parsed, then you'd notice the difference.

Consider a file containing aliases, lets call it alias, with an entry:

alias f="echo foo"

Now consider a script containing:

shopt -s expand_aliases
source ./alias
f

and another one containing:

shopt -s expand_aliases; source ./alias; f

then you might think that both would produce the same output.

The answer is NO. The first one would produce foo but the second one would report:

... f: command not found

To clarify further, it's not expand_aliases that's causing the problem. The problem is due to the fact that a statement like:

alias f="echo foo"; f

would be parsed in one go. The shell doesn't really know what f is, this causes the parser to choke.

devnull
  • 10,691
  • OK then my qeustion should have been with command ; command2; command3 – Kiwy Apr 02 '14 at 09:50
  • @Kiwy You mean ; instead of &&? – devnull Apr 02 '14 at 09:52
  • so indeed the context of execution make the execution of a script and an interactive script behave differently mainly because of bash variable ? – Kiwy Apr 02 '14 at 10:26
  • @Kiwy Environment variable? – devnull Apr 02 '14 at 10:28
  • well variable related to the execution env ? is it unclear (maybe i'm using a french formulation) ? – Kiwy Apr 02 '14 at 12:14
  • Could you explain why? It is something to do with aliases being available only after they've been read but why is ; not enough? Why is the new line necessary? – terdon Apr 02 '14 at 15:31
  • @terdon That's how the parser works. A simpler example is alias foo="echo bar"; foo. – devnull Apr 02 '14 at 15:38
  • @terdon Another example is shopt -s extglob; echo foo.@(bar). When separated by newline, it'd work but not if separated by a ;. – devnull Apr 02 '14 at 15:42
  • I know, I tried that and it works only with a newline. My question is why, I had always thought that ; is the equivalent of a newline in a script. – terdon Apr 02 '14 at 15:43
  • 2
    @terdon Bash parses an entire statement block before evaluating any of it. A ; doesn't cause the previous command to be evaluated. As such, the parser chokes on encountering an unknown command. – devnull Apr 02 '14 at 15:46
  • Ah! That's what I was looking for, thanks! – terdon Apr 02 '14 at 15:47
  • @terdon You knew that, didn't you? – devnull Apr 02 '14 at 15:48
  • Yes dammit, but had only encountered it in the context of function definitions and it didn't click on this example. Obvious in hindsight. – terdon Apr 02 '14 at 15:50
6

Yes, && is condition. Command behind will be started only if the previous one returns 0 (ends without an error). On the other hand your script hasn't this control so if eg. wget ends with error it will continue and try to unzip and move nothing..

Onliner for your script is:

wget http://something.com ; unzip something ; mv -f something /home/poney/
stderr
  • 986
2

Another difference to the one mentioned is that your shell script runs in a separate shell, therefore any changes to the environment won't propagate out. For example, if you type in your interactive shell

test -f foo && file=foo || file=other

then your interactive shell will contain a variable file (which you can read with $file) containing foo if the file foo exists and is a regular file, and other otherwise. Now if you put the same in a shell script and call that from your interactive shell, then the variable file in your interactive shell will not be set (but of course inside your shell script it will be set, so you can use it in further commands therein).

celtschk
  • 10,844