17

What is the good common practice to store shell scripts? (bash, sh, ...)

For now, I have a few bash and sh scripts in my $HOME directory

and I invoke them with

$ bash $HOME/script1.bash arg1, arg2, ...

or

$ sh $HOME/script2.sh arg1, arg2, ...

May I store them in some standard location and invoke them as normal apps like ls, pwd, ...? e.g.

$ script1 arg1, arg2, ...
$ script2 arg1, arg2, ...

What is common practice here for advanced linux users?

HalosGhost
  • 4,790
xralf
  • 15,415
  • 3
    BTW, putting .sh or .bash extensions on your scripts is not a best practice. Executable scripts define commands, and UNIX command names don't have extensions. You don't run ls.elf, do you? – Charles Duffy May 06 '15 at 17:47

5 Answers5

21

You could store your scripts where they belong in the filesystem, and create a bin directory in your home. Adding

if [ -d "$HOME/bin" ] ; then
    export PATH="$HOME/bin:$PATH"
fi

in your .bashrc makes any executable placed in ~/bin discoverable. Finally, you just need to add files in the dorectory. You can use symbolic links to whatever script you want to make discoverable in ~/bin, which allows you to virtually change the name of the script and leave it where you want it on you filesystem. As an example, for a file my_script.sh, first make sure the file is executable

chmod u+x my_script.sh

then create a symbolic link

ln -s my_script.sh ~/bin/my_script

in the dedicated folder. Note that the extension was removed for convenience. You can now run your script from anywhere using the command my_script. You don't have to make the symbolic link every time you edit the original my_script.sh file.

Edit : to make any text file executable via a certain interpreter, you can use a shebang. For a bash script, this means adding

#!/bin/bash

as a first line for the file. Note that the technique is not restricted to bash scripts, but also applies to python for instance using

#!/usr/bin/env python

Note : I personnally use ~/.local/bin instead if ~/bin as a personal preference, but most people use a bin directory directly located in their home, not hidden. Many distributions integrate it directly, such as debian or ubuntu which automatically add such a directory in the PATH if it exists (in the default .profile file they ship). My choice is based on the fact that many softwares already use .local/share, that I consider it as a configuration tool rather than as a set of real files (only symbolic links), and that I don't want this folder to mess with the completion.

  • OK, and can you execute the scripts without writing interpreter name, as if they were normal apps? – xralf May 06 '15 at 13:32
  • 3
    What does determine "where they belong in my filesystem"? – Anthon May 06 '15 at 13:38
  • This means where I can naturally find this file again. Most of my scripts are located in the same script directory, but I am not willing to make that whole directory part of the PATH in case I am experimenting some new script for instance. This technique allows me to easily control and find the set of reachable executables, since they are all linked to in the same place. For programs I compile, the final executable is often generated along with other exeutable files e.g. dynamic link libraries for instance, which should not belong to the global executables. – Vincent Nivoliers May 06 '15 at 13:40
  • 1
    Of course, you'll have to make the scripts executable, using something like chmod a+x script1.sh – daniel kullmann May 06 '15 at 13:44
  • 2
    Most of it is good advice, but why bother hiding your bin in .local? The standard location for these things is $HOME/bin. – alexis May 06 '15 at 14:34
  • @alexis applications already use .local/share without me messing around. I found it natural to add .local/bin and .local/lib for my personal applications and libraries. I believe my reason for that is that I consider this as part of my convenient configuration, and not real data. But I admit that this is my personal preference. I'll add a note about that. – Vincent Nivoliers May 06 '15 at 14:40
  • The applications are hiding their state by putting it in the dotted directory .local/share, but your bin is part of your operating environment-- of course it's not data but it's also not noise. As you can see from the other answers, the standard location is ~/bin. I actually use several directories depending on what it is, but none of them are hidden. – alexis May 06 '15 at 14:49
  • @alexis I edited my post to make it more clear that ~/bin is common, and that .local/bin is my own choice. I am not sure it can truly be called standard, since it is not automatically used in Arch for instance, but this is another debate. Thanks for your feedback anyway. – Vincent Nivoliers May 06 '15 at 14:57
  • Looks good. Your advice about leaving scripts elsewhere and linking is often appropriate, you could explain more (and add the ln -s while you're at it). – alexis May 06 '15 at 15:03
  • Why do they "belong in" ~/bin if they aren't binaries? – Superbest May 06 '15 at 20:28
  • Creating a symlink is not necessary. – Sildoreth May 06 '15 at 21:13
  • You probably need to run source ~/.bashrc for your changes to the .bashrc file to take effect. – zeusstl Mar 01 '19 at 20:28
9

The common path for such scripts is $HOME/bin. If such path is not in the $PATH, you should add

PATH=$HOME/bin:$PATH

to your .profile, .bash_profile, or .bashrc file.

choroba
  • 47,233
  • 1
    $HOME/bin is what I've always seen used. I don't know if it is LSB or POSIX, but it is very common. – SailorCire May 06 '15 at 13:44
  • @SailorCire it may be because ubuntu and debian at least ship a default .profile adding $HOME/bin to the PATH see here for instance. – Vincent Nivoliers May 06 '15 at 13:57
  • @VincentNivoliers I'm not a Ubuntu user, but one of those dirty rpm distro people (OpenSuSE and CentOS). – SailorCire May 06 '15 at 13:59
  • 1
    When I'm writing homemade scripts or programs to be used regularly on a system, I tend to install them in /usr/local/bin, as it would be done if I used an autotools build toolchain for them. This is a common location for executables that do not come from packages or other "more official" sources. – John WH Smith May 06 '15 at 14:29
  • 1
    @JohnWHSmith for system wide hand written scripts this makes sense and is "correct". It is not wise for anything else. See FHS for more details. – SailorCire May 06 '15 at 14:37
7

There are several steps to managing your shell scripts as real programs.

  1. Turn on executable mode for your script:

    chmod +x myscript.sh
    
  2. Start your script with an interpreter string (signaled by #!, the "hash-bang") that tells the system how to run your script (the default is a shell script, but don't rely on it).

     #!/bin/bash
    
  3. Collect your scripts (along with compiled programs, it makes no difference) in a directory, and put this directory in your execution PATH. The customary place for your own scripts is $HOME/bin, but it's really up to you.

    Put this in your ~/.profile and future shells will find your scripts exactly the way they find ls or make. (Unless the latter are aliases, of course :-))

    export PATH="$HOME/bin:$PATH"
    
  4. Unix, unlike Windows, will not ignore the extension of executable files. If your script is called myscript.sh, you've got to type myscript.sh to run it. So rename it to myscript-- the first line of the source tells you what kind of a script it is anyway.

    mv myscript.sh myscript
    

myscript is now a completely ordinary command, that you can run like everything else. If it is named the same as an executable already in your PATH, it will take precedence since we put $HOME/bin first. (You can put it at the end if you prefer.)

alexis
  • 5,759
1

You can store your scripts in a dedicated directory and then add that directory to your PATH variable. PATH is the way your system knows where to look for executables.

Erathiel
  • 1,575
0

Yes, it is possible to set it up so that you can invoke your scripts by name regardless of your working directory.

Steps

  1. Make sure that the files in the directory are executable with chmod
  2. If it's a script rather than a binary executable, make sure the script starts with an appropriate shebang.
  3. Make sure the directory containing the file is in PATH.
    • But make sure it's an appropriate directory first (see next section)
  4. If you want the script to be accessible via a simple command name, either remove the file extension or create a symlink with the desired name in the directory.
    • This is completely optional
    • To create a symlink: ln -s origfile linkname

Where to place the scripts

Now, in what directory should you put the executables? Ultimately, this comes down to how visible you want your scripts to be on the system:

  • If you are a system admin and want everyone on the system to be able to run the scripts, place them in /usr/local/bin.
    • This directory is already in PATH by default on many systems
  • If you want them to only be accessible to you, place them in ~/bin.

This other post has some useful information on the topic of where executable scripts and binaries should be placed: How do I know where to put things in linux?.

Sildoreth
  • 1,884