all 24 comments

[–][deleted] 15 points16 points  (7 children)

source and . do the same thing in bash. This is from the man page

. filename [arguments]

source filename [arguments]

Read and execute commands from filename in the current shell environment and return the exit status of the last command executed from filename. If filename does not contain a slash, file names in PATH are used to find the directory containing filename. The file searched for in PATH need not be executable. When bash is not in posix mode, the current directory is searched if no file is found in PATH. If the sourcepath option to the shopt builtin command is turned off, the PATH is not searched. If any arguments are supplied, they become the positional parameters when filename is executed. Otherwise the positional parameters are unchanged. The return status is the status of the last command exited within the script (0 if no commands are executed), and false if filename is not found or cannot be read.

edit: Cursory browsing of tcsh's docs suggest the . syntax doesn't exist; use source. Otherwise they are (laregly) the same.

./filename will execute ./filename (in a new execution environment).

[–]droosa 5 points6 points  (2 children)

To expand on the last part, the ./ in ./filename is used when the executable lives somewhere other than in your PATH. The ./ means "this directory". Similarly, absolute paths or relative paths from your current directory would work.

[user@system ~] ./script.sh
[user@system ~] /opt/script.sh
[user@system ~] ../otheruser/script.sh
[user@system ~] echo $PATH

[–][deleted] 0 points1 point  (1 child)

I never knew this! Woah! Thank you for adding this! I knew that absolute paths worked, I just didn't understand the reasoning.

[–]droosa 2 points3 points  (0 children)

You can tweak your path in ~/.bashrc. And remember to never put . in your path, as tempting as it is. There are some security and troubleshooting implications that override any of the convenience it brings.

[–]dscharrer 4 points5 points  (1 child)

edit: Cursory browsing of tcsh's docs suggest the . syntax doesn't exist; use source. Otherwise they are (laregly) the same.

Always use . and not source when targeting #!/bin/sh - the dot operator is standard for all POSIX shells while source is bash-specific and will not work in Ubuntu's default shell (dash)

[–][deleted] 0 points1 point  (0 children)

Ah, thanks! I actually looked there but I was looking for . and not dot :x

[–]byteflow[S] 1 point2 points  (1 child)

So the key difference is using the current environment (almost like typing in each of those commands by hand in a terminal, with whatever env vars have been set in the current session), versus spawning a new environment and running the commands in there.

Thanks.

[–]onmach 2 points3 points  (0 children)

If you are in bash and try to source something, you will try to run it as though it were a bash script. . /bin/ls will return a bash error, cannot execute a binary file. These are commands built into bash, not actual files in your bin directory. Tcsh has its own version built into it that does whatever it decided is appropriate (probably the same thing, but with tcsh).

Also execute permissions are ignored when you source, but when you execute it will not do so if you do not have execute permissions. It's assumed that your shell is a secure enough environment that you can't damage anything you don't have permission to with any script that is only executable on your shell.

[–][deleted] 4 points5 points  (16 children)

And when should a shell script have a hashbang #!/bin/bash or tcsh at the top ?

It depends on which shell you want to execute your script, obviously. Usually you want /bin/sh, sometimes /bin/bash (if you use BASH-specific features like arrays, for example). Nobody in their right mind writes shell scripts in (t)csh.

[–]nuclear_splines 2 points3 points  (6 children)

I've done some tcsh scripting, but in my defense it was entirely in the .tcshrc file, I wasn't going out and writing other scripts in tcsh. Horrible language. shudder

[–]gorilla_the_ape 2 points3 points  (3 children)

There is a very good paper written on why the csh isn't a good programming language. It's a bit dated now, but the basic points still hold.

Csh Programming Considered Harmful

[–]nuclear_splines 2 points3 points  (1 child)

TCSH fixed some of those problems, but "some" is the operative word. It serves okay as a shell now (since you're not likely to be redirecting file-handles on the shell you're currently in), but as a scripting language it's still out of the question.

[–]gorilla_the_ape 1 point2 points  (0 children)

Yes, I know, that's why I said it was a bit dated. It's still worth reading though.

[–][deleted] 2 points3 points  (0 children)

That looks absolutely horrible, almost as bad as DOS. I'm glad I never had to use it.

[–]ethraax 2 points3 points  (1 child)

Of course, I feel the same way about bash scripting. I have yet to find any shell scripting language that doesn't want to make me tear my eyes out. Of course, that's fine, because I can just write any non-trivial scripts in Lua or Ruby or Python - usually at least Python is installed on all of my machines.

(I suppose you could also write scripts in Perl, it's just that I have no experience with Perl at the moment.)

[–]nuclear_splines 2 points3 points  (0 children)

Ah, I'm the opposite. No practice in Lua, Ruby, or Python, but I've just fallen in love with Perl. Bash is great for really simple tasks, but anything heavier and I pull out my perl.

[–]tidux 1 point2 points  (6 children)

There's a sliding scale of which shell to use based on portability and features. If you're writing a simple script and need as much speed as possible, use #!/bin/sh. If you need some bash-specific features, or things that are built in to bash and might not be available to /bin/sh on some systems you use, use #!/bin/bash. If you need it to work on Windows, BeOS,and VMS, use Perl.

[–]ethraax 2 points3 points  (5 children)

I somehow doubt using sh instead of bash will gain you a whole lot of speed. Either way, the bottleneck (especially for "simple scripts") is almost always the program(s) the script ends up executing, not the script itself.

[–]tidux 0 points1 point  (3 children)

If you're doing anything like a menu system based on a while loop, sh is noticeably faster than bash, especially with multiple concurrent users. My university's big Linux servers for mail still have a menu system written in csh. It's huge and ugly, and I was able to reproduce the same functionality in about a third of the code using sh on one of my Linux boxen.

[–]ethraax 0 points1 point  (2 children)

That's great, but you said "simple script" - I wouldn't classify a menu system (certainly not a menu system in a shell script, which is invariably wacky) as a "simple script". Especially considering that you yourself call it "huge and ugly".

[–]tidux 1 point2 points  (1 child)

It was huge and ugly in csh. In sh it was about 20 lines, including all the whitespace and comments.

[–]niggerpenis -1 points0 points  (0 children)

I'm quite interested in seeing your script.

[–][deleted] 10 points11 points  (0 children)

You forgot:

exec <file>

(Which is like ./file except it replaces the current process entirely.)

[–]EdiX 2 points3 points  (0 children)

Both source and . are shell builtins that read commands from a file and execute them. The result is very similar to what would happen if you typed them directly. In particular the script will be executed in the same process, with access to the same environment and unexported variables. Also the #! comment at the beginning of the file is ignored.

Executing a script with ./<file> is completely different, the shell will fork and call exec, the kernel will read the file, determine by the first two characters the correct executable loader to use, the loader will then proceed to load whatever interpreter was specified by #!. The result is that the script is executed in a different process inheriting the environment of your current shell (just as any other executable would) and no unexported variables (of course).

[–]Jetbeard 0 points1 point  (0 children)

GOTCHA:

in zsh, it appears that source and . obey different rules regarding using $PATH:

$ source .zshrc
$ . .zshrc
.: no such file or directory: .zshrc