.sh specifying extension?

You're confused. The .sh extension is only a hint to humans, and has absolutely NO effect on how the system handles the file. Unix/Linux did not make the Windows' Secrets.pdf.exe blunder.

Here is what happens when you type foo:

  1. Redirection for STDIN, STDOUT and STDERR are set up.

  2. The shell checks its internal hash table to see if it already knows a $PATH entry for foo. If none exists, the shell searches the directories in $PATH, looking for a file called foo that has the Execute bit set in it's file permissions. First foo wins.

  3. If the first two bytes of the file foo are #!, the next string is the name of an interpreter to run. Thus #!/bin/bash introduces a Bash script, #!/usr/bin/perl introduces a Perl script, etc.

  4. If the file starts with \177ELF, it's a binary executable, and ld.so starts it.

Read man execve and man ld.so for a more detailed explanation.


Key point is this: Extensions are irrelevant in any Unix-like system system.A filename is just name and has no effect on whether or not script or compiled executable can run. A programmer may add a .sh extension to designate that a file is shell script, or .py for python script, but unlike Windows , any unix doesn't care about naming, it cares about permissions.

What matters is the executable permission granted to a file. Which you can check with

ls -l /path/to/file

Running executables

To run script there are generally several ways.

  • If your current directory is the same as the script, and script has executable permissions you can run it like so ./my_script_name . The . means current directory.
  • If your current directory is different and script has executable permissions, you can run it by specifying full path: /home/user/bin/my_script_name

(The above two methods rely on having executable permission set ; whether or not file is part of $PATH variable is irrelevant. Presence of #! line also matters; without it, it the script will be executed by the current shell you have open. If I have csh script without that line, and try to run it in bash with ./my_script.csh , it will fail)

  • If your script is located in directory that is part of your $PATH variable, you can run it just by calling the name. You can call chmod command in command line just by typing its name because it's in /bin folder. /bin is always part of $PATH variable. In this case executable permissions and location of the script matter
  • Specifying an interpreter as command and script as argument. That way script will serve as input file to the interpreter.
  • Sourcing a file. The . filename.sh or source filename.sh will make the script be treated as if it was keyboard input, i.e. as if it was typed into command line directly. In this case executable permissions and location don't matter

Examples

Example #1 , running with interpreter, to exec permissions

$-> ls -l abc.py                                                               
-rw-rw-r-- 1 xieerqi xieerqi 44 Apr 27 22:39 abc.py
$-> python abc.py                                                              
a
b
c

Example #2, running with ./ executable permission set, shebang line set.

$-> cat abc.py                                                                 
#!/usr/bin/env python
for letter in 'a' 'b' 'c' :
   print letter
$-> ls -l abc.py
-rwxrwxr-x 1 xieerqi xieerqi 66 Apr 27 23:02 abc.py*
$-> ./abc.py                                                                   
a
b
c

Example #3, running without shebang line set (fails, because bash can't read python scripts ; no shebang line assumes current shell as interpreter )

$-> cat abc.py                                                                 
for letter in 'a' 'b' 'c' :
   print letter
$-> ./abc.py                                                                   
./abc.py: 2: ./abc.py: Syntax error: word unexpected (expecting "do")

Example #4 , running script that has executable permissions set form folder that is part of $PATH variable

#  /home/xieerqi/bin is part of my path variable
$-> echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/opt/microchip/xc16/v1.25/bin:/opt/microchip/xc32/v1.40/bin:/opt/microchip/xc8/v1.35/bin:/home/xieerqi/bin:/home/xieerqi/bin/sh

$-> # current directory is /home/xieerqi
$-> pwd
/home/xieerqi
$-> # move the file to ~/bin
$-> mv ~/abc.py ~/bin/abc.py
$-> # now I can run it just by calling the name
$-> abc.py
/home/xieerqi/bin/abc.py: 2: /home/xieerqi/bin/abc.py: Syntax error: word unexpected (expecting "do")
$-> # Syntax error because again, no interpreter specified.                    
$-> # must add #!/usr/bin/env python
$-> vi /home/xieerqi/bin/abc.py          
$-> # after adding the line with vi text editor, we can run
$-> abc.py                                                                     
a
b
c

Example #5, removing extension, still runs because extensions don't matter, but it has permissions and is part of $PATH :

$-> mv ~/bin/abc.py  ~/bin/abc                                                 
$-> abc
a
b
c

Good explanations here already. I just wanted to add that ideally you shouldn't use file extensions for executables.

Usually you need to accomplish something relatively easy and you start with a little shell script. Over time you start adding more and more functionality to your script, until it arrives some time that it becomes unmaintainable or you need some functionality that you can't accomplish easily with a shell script and think about rewriting this shell script in another language (python, perl, ... ?).

Rewriting from scratch is usually considered an error, but for scripts it may make sense because usually they are not that large or have lots of functionality. But let's assume that it is feasible to rewrite from scratch in some other language, maintaining the functionality and params/flags of the initial shell script.

Users of this script do not need to be aware of this language change, they will keep executing the same command and it will continue working.

If your script was named do-something.sh, it can continue being do-something.sh, but now it is written in python (for example), and so your initial hint is now a totally misleading one.