84

I have some functional scripts and I want to copy to /usr/bin I want to use them as normal terminal commands. Is it a good practice to use them with the .sh extension or can I save them without extension?

Sri
  • 1,662
  • 2
  • 20
  • 39
Patterson
  • 1,360
  • 5
  • 16
  • 26
  • 7
    Also if you want those scripts to be available to all users, /usr/local/bin may be a better choice. – Salem Jul 26 '14 at 23:02
  • 7
    @Salem /usr/bin and /usr/local/bin should both be available to all users, but /usr/local/bin is better for executables that are not part of packages. – gerrit Jul 27 '14 at 01:13
  • The only benefit I've seen is that editors such as vim or nano know how to highlight right from the start, and that's about it. – rath Jul 27 '14 at 02:19
  • 2
    @rath I get syntax highlighting without the extension if I have the shebang set to #!/usr/bin/env bash or #!/bin/bash. – Sparhawk Jul 27 '14 at 05:54
  • @Sparhawk Indeed but I often forget it till I try to run the script ;) – rath Jul 27 '14 at 22:27
  • @gerrit, Do you mind elaborating? Why /usr/local/bin is better for executables that are not part of packages? – Pacerier Sep 15 '15 at 09:48
  • @Pacerier That's a separate question that I'm sure many others can answer a lot better than me. I'd just say "it's the standard". – gerrit Sep 15 '15 at 10:07
  • @rath, that seems like a pretty good reason to do it then, no? – jterm May 24 '18 at 13:54
  • @rath, what version of vim are you using that can't figure out syntax highlighting from the shebang? – Charles Duffy Mar 26 '20 at 01:32
  • More useful would be to have shebangs on top so whatever program you use to run them will recognize them quickly. – JuanFraItu Jul 06 '22 at 19:30

4 Answers4

91

No, it is not a good practice, you should keep your scripts without extension. Note, that scripts being part of packages doesn't have a .sh extension, i.e. update-grub, not update-grub.sh. If you are still not convinced, then be advised, that Google Shell Style Guide says:

Executables should have no extension (strongly preferred) or a .sh extension. Libraries must have a .sh extension and should not be executable.

PS You don't have to put your script into /bin. You can create directory ~/bin and put your script there. Directory ~/bin is included in $PATH by default, so scripts put there can be run as any other shell command.

  • 5
    "Directory ~/bin is included in $PATH by default" - Since when? Anyway, ~/.local/bin is probably a better choice as it's a standard. – Alexia Luna Jul 27 '14 at 11:07
  • 1
    You mean "Libraries must have a .so extension", right? Not sh. – Keith Wolters Jul 27 '14 at 13:39
  • 7
    @KeithWolters first, not me, but Google. Second, .sh, not .so, we are talking about shell scripts, not binaries. –  Jul 27 '14 at 14:00
  • 5
    The Google style guide is very specific to Google. For example, "Bash is the only shell scripting language permitted for executables." Clearly an internal rule rather than best practices. – Paul Draper Dec 08 '14 at 08:33
  • @PaulDraper Note, that scripts being part of packages doesn't have a .sh extension, i.e. update-grub, not update-grub.sh. –  Dec 08 '14 at 11:42
  • 2
    @nyuszika7h check out ~/.profile... it inserts $HOME/bin into your path if the directory exists – Corey Goldberg Feb 24 '16 at 01:31
  • For what it's worth, the bash-4.4 tag has many files beginning with #!/bin/sh sporting a .sh extension. I'd sooner consider GNU an authority than Google. The ultimate advantage is for the coder. Someone looking to modify an executables behavior can recognize the .sh extension immediately and happily edit in vi. Otherwise, it's off to search for source code, recompile. Omitting the extension just complicates this. It also makes grep far less specific. As this is programmer's land, I say keep the .sh. – Brian Sep 19 '17 at 16:27
  • 1
    Would upvote an answer that actually says why script files should not end in .sh. – Bob Stein Jul 19 '18 at 16:11
  • 2
    @BobStein See https://www.talisman.org/~erlkonig/documents/commandname-extensions-considered-harmful/, and the history of freenode #bash channel factoids on the topic at http://wooledge.org/~greybot/meta/.sh – Charles Duffy Mar 26 '20 at 01:26
  • @Brian, the essay linked above may be of interest to you as well. – Charles Duffy Mar 26 '20 at 02:55
11

I second the recommendation to use ~/bin which gets automatically added to your $PATH,as Sergey said. Or /usr/local/bin, which may already be on the PATH. However:

  • You are doing this for yourself. Use whatever you feel comfortable with. Indeed, I'd say keep the extension so that you'll be reminded it's your script you are running, since -
  • Extensions are uncommon in /usr/bin. In my system, I can find only two:

    $ dpkg -S `ls /usr/bin/*.sh`
    mtools: /usr/bin/amuFormat.sh
    gettext-base: /usr/bin/gettext.sh
    

    So if you are packaging, definitely leave out the extension.

muru
  • 197,895
  • 55
  • 485
  • 740
  • 2
    ~/bin is added to the $PATH automatically if it exists, no need to add it manually. Just create the directory, log out and log back in. – Sergey Jul 29 '14 at 21:03
7

Just put following line at top of file:

#!/bin/bash

So-that file will be automatically type : Shell Script without any extension!

Remember to give execution permission to file.

For putting script so-that can be run by direct command, visit: Where should I put my script so that I can run it by a direct command?

Pandya
  • 35,771
  • 44
  • 128
  • 188
1

Your scripts and the commands that run them don't need to have the same name

I agree with the opinions and advice in other answers here, in that typed commands shouldn't have an extension (mycmd, not mycmd.sh), and that editors should be able to identify the file contents from the shebang line (e.g. #!/bin/bash).

However, if the scripts are part of a larger project, I find it useful to have file name extensions on them to remind myself whether the files in the repo are editable (e.g. scripts, source code), or compiled binary files.

To achieve both aims, you can symlink your scripts from the directory on your PATH. E.g. if ~/.local/bin is on your PATH:

cd ~/.local/bin
ln -s ../../path/to/code/project/src/mycmd.sh mycmd

now mycmd is on the PATH, and calling mycmd runs the script mycmd.sh

cd somewhere/else mycmd

This also allows you to do version control from ~/path/to/code/project/, without then having to copy the files into a directory on your PATH when you do a "release".