How to run a shell script on a Unix console or Mac terminal?
To run a non-executable sh
script, use:
sh myscript
To run a non-executable bash
script, use:
bash myscript
To start an executable (which is any file with executable permission); you just specify it by its path:
/foo/bar
/bin/bar
./bar
To make a script executable, give it the necessary permission:
chmod +x bar
./bar
When a file is executable, the kernel is responsible for figuring out how to execte it. For non-binaries, this is done by looking at the first line of the file. It should contain a hashbang
:
#! /usr/bin/env bash
The hashbang tells the kernel what program to run (in this case the command /usr/bin/env
is ran with the argument bash
). Then, the script is passed to the program (as second argument) along with all the arguments you gave the script as subsequent arguments.
That means every script that is executable should have a hashbang. If it doesn't, you're not telling the kernel what it is, and therefore the kernel doesn't know what program to use to interprete it. It could be bash
, perl
, python
, sh
, or something else. (In reality, the kernel will often use the user's default shell to interprete the file, which is very dangerous because it might not be the right interpreter at all or it might be able to parse some of it but with subtle behavioural differences such as is the case between sh
and bash
).
A note on /usr/bin/env
Most commonly, you'll see hash bangs like so:
#!/bin/bash
The result is that the kernel will run the program /bin/bash
to interpret the script. Unfortunately, bash
is not always shipped by default, and it is not always available in /bin
. While on Linux machines it usually is, there are a range of other POSIX machines where bash
ships in various locations, such as /usr/xpg/bin/bash
or /usr/local/bin/bash
.
To write a portable bash script, we can therefore not rely on hard-coding the location of the bash
program. POSIX already has a mechanism for dealing with that: PATH
. The idea is that you install your programs in one of the directories that are in PATH
and the system should be able to find your program when you want to run it by name.
Sadly, you cannot just do this:
#!bash
The kernel won't (some might) do a PATH
search for you. There is a program that can do a PATH
search for you, though, it's called env
. Luckily, nearly all systems have an env
program installed in /usr/bin
. So we start env
using a hardcoded path, which then does a PATH
search for bash
and runs it so that it can interpret your script:
#!/usr/bin/env bash
This approach has one downside: According to POSIX, the hashbang can have one argument. In this case, we use bash
as the argument to the env
program. That means we have no space left to pass arguments to bash
. So there's no way to convert something like #!/bin/bash -exu
to this scheme. You'll have to put set -exu
after the hashbang instead.
This approach also has another advantage: Some systems may ship with a /bin/bash
, but the user may not like it, may find it's buggy or outdated, and may have installed his own bash
somewhere else. This is often the case on OS X (Macs) where Apple ships an outdated /bin/bash
and users install an up-to-date /usr/local/bin/bash
using something like Homebrew. When you use the env
approach which does a PATH
search, you take the user's preference into account and use his preferred bash over the one his system shipped with.
Execute bash and sh file on Mac without writing extension
Two problems...
Firstly, file
is already an executable program in /usr/bin
that tells you the type of a file - i.e. whether it is an image, or a song or a database. Quick example:
file a.png
a.png: PNG image data, 1 x 1, 1-bit colormap, non-interlaced
So, file
is a bad name for a shell script - likewise is test
.
Secondly, if you want to execute a script or program in your current directory, also known as dot (.
), you either need to have dot in your PATH
, or you need to explicitly tell your shell that the file you want to run is in the current directory. The easier option is the second, which means if your script is called fred
, you run it with
./fred
which tells the shell it is in your current directory.
The longer option, if you want to always be able to run scripts in the current directory, is to add dot to your PATH. So, you locate your login script (probably $HOME/.profile) and you find the line that sets your PATH
and you add the current directory to it.
export PATH=$PATH:.
Once you have set that, you are best off logging out and back in to have it take effect.
Some folks disapprove of the idea of adding dot to their PATH - I don't. YMMV.
How to run shell script daily in Mac Os X?
Yes of course, you can use crontab!
Firstly open the terminal, then launch crontab with:
crontab -e
In some cases you need to specify the editor (es.nano) like this:
env EDITOR=nano crontab -e
Now you can add your daily script at 3am like this:
0 3 * * * sh /path/to/your/file
The format is:
min hour day_of_month month day_of_week your_command
After save the cron, you can check the crontab list whit:
crontab -l
And if you want remove it with:
crontab -r
How to run a shell script in OS X by double-clicking?
First in terminal make the script executable by typing the following command:
chmod a+x yourscriptname
Then, in Finder, right-click your file and select "Open with" and then "Other...".
Here you select the application you want the file to execute into, in this case it would be Terminal. To be able to select terminal you need to switch from "Recommended Applications" to "All Applications". (The Terminal.app application can be found in the Utilities folder)
NOTE that unless you don't want to associate all files with this extension to be run in terminal you should not have "Always Open With" checked.
After clicking OK you should be able to execute you script by simply double-clicking it.
Open new terminal in MacOSX and run node script
One way to do this would be to place the commands you want to run in a shell script with the .command
extension. By default, these files will be opened in the Terminal application on macOS. This is a bit of a workaround, but I think it achieves what you would like to do.
Say we have the file hello.js
containing the following:
console.log("Hello World")
And the shell script run_node.command
#!/bin/bash
node hello.js
Running the command open run_node.command
will open a new Terminal.app instance and run the shell script, which in turn runs the node command. The terminal will close when the script exits.
Related Topics
Rename All Files in a Folder With a Prefix in a Single Command
How to Remove Cached Credentials from Git
How to Use Sed to Extract Substring
How to Fix Java.Lang.Module.Findexception: Module Java.Se.Ee Not Found
How to Send a HTML Email With the Bash Command "Sendmail"
How to Split One Text File into Multiple *.Txt Files
Finding Number Is Even/Odd in Assembly
Python Code to Check If Service Is Running or Not.
How to Tar a Directory Without Retaining the Directory Structure
How to Find Which Position a Word Is in a String
How to Reload Google Chrome Tab from Terminal
How to Redirect the Output of the Time Command to a File in Linux
Use of Floating Point in the Linux Kernel
How to Setup Public-Key Authentication
Setting Environment Variables in Linux Using Bash
What Are the Return Values of System Calls in Assembly
Printing an Integer as a String With At&T Syntax, With Linux System Calls Instead of Printf