13

Why is it some systems will run a .sh file just by specifying the file name without extension and others require name plus extension? In my case I'm trying to write a series of commands following these instructions.

I'm specifying the extension now but being able to run the commands without .sh would be preferable.

  • 4
    Using .sh as an extension is in many circumstances considered bad practice: It's contrary to how other commands are named (you don't run ls.elf), it's often misleading (if your foo.sh starts with #!/bin/bash, then running sh foo.sh will run it with a different interpreter than it's built for), and if you rewrite foo.sh to be a Python program, using that extension means you need to choose between keeping the now-misleading name and rewriting every program that calls it. – Charles Duffy Apr 28 '16 at 21:39
  • 2
    ...where it is a best practice is shell libraries, not commands with +x set -- where foo.sh is a library that can be sourced into any POSIX shell, foo.bash can be sourced into bash, foo.ksh into ksh, etc. – Charles Duffy Apr 28 '16 at 21:39

5 Answers5

39

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.

waltinator
  • 36,399
  • 15
    Yes, on Linux you can double-click Secrets.pdf with no clue from the name that it's actually an executable ;) – OrangeDog Apr 28 '16 at 14:03
  • 1
    @OrangeDog I know you're joking, but I feel like I have to point out that the executable bit (chmod +x) pretty much solves this, right? – wchargin Apr 28 '16 at 15:35
  • 3
    @WChargin That depends how well-behaved your filesystem is (e.g. a mounted network share or NTFS partition might optimistically set the x bit on everything) and where the file came from (any process with control of the directory could be tricked into setting the permissions). So, it mitigates it, but I wouldn't say it solves it. – IMSoP Apr 28 '16 at 16:39
  • 2
    @WChargin, yet, but I think his point that usually file managers do not show the executable bit, i.e. there is not "hint to humans" like an extension. – Paul Draper Apr 28 '16 at 22:13
  • has absolutely NO effect on how the system handles the file That's mostly true, but still an overgeneralization. Desktop environments usually care about extensions. For example, a shell script without extension and without shebang in KDE's Autostart folder will render the user's account useless. – Dennis Apr 29 '16 at 02:51
  • @Dennis why? If there's no shebang, an executable script is executed with /bin/sh as the interpreter (see "Sepcial semantics in man 3 exec). – muru Apr 29 '16 at 02:59
  • @muru I have no idea why, but that's what happens. (I discovered that the hard way.) – Dennis Apr 29 '16 at 03:02
  • 1
    I never mistakenly click on Secrets.pdf.exe because I always disable the stupid hide file extension feature – phuclv Apr 29 '16 at 03:35
13

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
Sergiy Kolodyazhnyy
  • 105,154
  • 20
  • 279
  • 497
6

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.

5

To run files without an extension you normaly dont need to do much, just make sure you have (in case of bash scripts) the proper shebang line at the very first line:

#!/bin/bash

then you aswell need tho make the file executable for the system by

chmod 755 yourfilename

This is the same as using chmod +x yourfilename the numbers are easy explained.

It is a number triple of added octals, the first number stands for the user, the second one for the group, and the third one for others, more on that you can find here.

And if you are in the same directory as your script dont forget to use ./ like this:

./yourfilename
Videonauth
  • 33,355
  • 17
  • 105
  • 120
0

The .sh suffix can actually get in the way, because then to run it you have to type myscript.sh instead of just myscript which won't work. Better to just call it "myscript" without the .sh suffix, and a quick use of the "file" command will tell you if it's a binary executable (ELF format on linux) or a shell script, or whatever other kind of script.

QDOS (Quick and Dirty Operating System, later renamed to "DOS" by IBM after mirosoft pirated it and illegally sold it to them) and other cheap ripoffs of CP/M, including windows, mix all of this up because on those systems there's no such thing as execute permissions on files. This has resulted in countless security f'ups in the past 30-40 years. Actually just a few minutes ago i just got several junk mails with a booby trapped zip file renamed to MYPICTURE.JPG.zip :)

delt
  • 333