What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Some links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.

A shell script is a plain-text file containing commands. On Ubuntu, you can create one with nano, make it executable with chmod, and run it from Terminal with ./script.sh.

mkdir -p ~/scripts
cd ~/scripts
nano hello.sh

Enter the following, save it, then run:

#!/usr/bin/env bash

echo "Hello from Ubuntu"
chmod u+x hello.sh
./hello.sh

Expected output:

Hello from Ubuntu

The quickest way to create and run a script

These instructions work in Ubuntu Desktop and Ubuntu Server. You do not need a compiler or special runtime for basic Bash scripts. Create the file in a directory you own rather than in /usr, /bin, or another system directory.

  1. Open Terminal.
  2. Create a personal scripts directory and enter it:
    mkdir -p ~/scripts
    cd ~/scripts
  3. Open a new file in nano:
    nano hello.sh
  4. Enter:
    #!/usr/bin/env bash
    
    echo "Hello from Ubuntu"
  5. Save with Ctrl+O, press Enter to confirm the filename, and exit with Ctrl+X.
  6. Add execute permission and run it:
    chmod u+x hello.sh
    ./hello.sh

The .sh suffix is a useful naming convention, but it does not make a file executable. The file is simply a text file until you give it execute permission or explicitly pass it to an interpreter.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

What the shebang means

The first line, #!/usr/bin/env bash, is called a shebang. When you launch the file directly with ./hello.sh, it tells the operating system to find and use Bash. Bash’s documentation covers script files, shebangs, permissions, and positional parameters in its shell-script documentation.

#!/bin/bash is another conventional form. The fixed path is explicit, while /usr/bin/env bash searches for Bash through PATH. Use a Bash shebang when the script contains Bash-specific syntax. A script beginning with #!/bin/sh should use POSIX sh syntax instead.

The blank line is optional. echo prints text to standard output. Lines beginning with # are comments, except for the first-line shebang, which has interpreter significance. Quoting affects variables, spaces, metacharacters, and expansions; see the GNU Bash references for shell syntax and quoting.

Create a script without an editor

On a minimal server or SSH session, you can create the same file with a here-document:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
cat > hello.sh <<'EOF'
#!/usr/bin/env bash

echo "Hello from Ubuntu"
EOF

This creates or replaces hello.sh. The > operator overwrites an existing file, so check the filename before running the command.

You can also use vim, emacs, Visual Studio Code, or a graphical text editor. The editor does not determine whether the script works; its contents, interpreter, line endings, and permissions do.

Make the script executable

chmod u+x hello.sh

chmod changes file permissions. The u+x form adds execute permission for the file’s owner, which is usually the smallest change needed for a personal script. You can also use:

chmod +x hello.sh

This adds execute permission for applicable permission classes according to the existing mode. Verify the result with:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
ls -l hello.sh

A result might include -rwxr--r--; the exact owner, group, date, and permissions vary. Direct execution requires the execute bit, but bash hello.sh does not.

Do not use chmod 777 as a general fix. It grants read, write, and execute permissions broadly. Likewise, do not use sudo to create or run an ordinary user-owned script unless a specific command genuinely needs elevated privileges.

Three ways to run a script

Command Execute permission? Interpreter
./hello.sh Yes The interpreter in the shebang
bash hello.sh No Bash explicitly
sh hello.sh No sh explicitly

Direct execution: ./hello.sh

The ./ means “the file named hello.sh in the current directory.” Ubuntu generally does not search the current directory for commands, so typing only hello.sh commonly produces command not found. Direct execution tests both the file’s execute permission and its shebang.

Explicitly use Bash: bash hello.sh

Bash opens and executes the file, so the execute bit is unnecessary and the shebang is not used to select the interpreter. This is useful for testing or for a script whose executable metadata was lost. Bash’s invocation behavior is documented in the Bash manual.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Use sh only for POSIX shell scripts

sh does not necessarily mean Bash. A Bash script using arrays, [[ ... ]], associative arrays, mapfile, process substitution, or other Bash-only features may fail when run with sh. Choose one interpreter and write syntax compatible with it.

Pass arguments to a script

Save this as show-args.sh:

#!/usr/bin/env bash

echo "Script name: $0"
echo "First argument: $1"
echo "All arguments: $@"

for item in "$@"; do
    printf 'Item: %sn' "$item"
done

Run it with:

chmod u+x show-args.sh
./show-args.sh apple "red banana"

$0 is the name used to invoke the script, $1 is the first argument, and $2 is the second. Use "$@", rather than unquoted $@, when you need to preserve each argument as a separate item. Quoted variables also protect filenames and values containing spaces from unintended word splitting and filename expansion.

A practical system-information script

This Bash example uses variables, command substitution, printf, and multiple commands:

#!/usr/bin/env bash

printf 'User: %sn' "$USER"
printf 'Home: %sn' "$HOME"
printf 'Working directory: %sn' "$PWD"
printf 'Date: %sn' "$(date)"
printf 'Kernel: %sn' "$(uname -sr)"

Save it as system-info.sh, then run:

chmod u+x system-info.sh
./system-info.sh

Check and debug a script

Check Bash syntax without executing the script:

bash -n hello.sh

Trace commands as Bash executes them:

bash -x hello.sh

You can also temporarily place set -x in the script. For additional static analysis, install or use ShellCheck if it is available:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
shellcheck hello.sh

ShellCheck can identify many quoting and syntax problems, but it is not a substitute for understanding what a script will do.

Exit statuses

Commands conventionally return status 0 for success and a nonzero value for failure. For example:

#!/usr/bin/env bash

echo "Task completed"
exit 0

After running the script, inspect the status immediately:

./hello.sh
echo $?

If a script does not explicitly call exit, Bash normally returns the status of its last command. Bash documents invocation and exit-status behavior in its invocation reference.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

A simple failure check might look like this:

#!/usr/bin/env bash

if [[ ! -f "$1" ]]; then
    printf 'Error: file not found: %sn' "$1" >&2
    exit 1
fi

printf 'File exists: %sn' "$1"

Understand the working directory

A script normally starts in the caller’s current working directory. It does not automatically run from the directory where it is stored. Check the current directory with:

pwd

If a Bash script needs files located beside the script itself, calculate that directory explicitly:

#!/usr/bin/env bash

script_dir="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
printf 'Script directory: %sn' "$script_dir"

This is Bash-specific. Alternatively, use carefully constructed absolute paths.

Run a script from another directory

Use a relative or absolute path:

~/scripts/hello.sh
bash ~/scripts/hello.sh
bash "$HOME/My Scripts/hello.sh"

Spaces are valid in filenames, but the path must be quoted. For command-line simplicity, names without spaces are usually easier to manage.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Make a personal script available as a command

Once the script works, place a copy in your personal executable directory:

mkdir -p ~/.local/bin
cp hello.sh ~/.local/bin/hello
chmod u+x ~/.local/bin/hello

If that directory is in PATH, run:

hello
command -v hello

For a temporary test when it is not already in PATH:

export PATH="$HOME/.local/bin:$PATH"
hello

Command lookup uses the directories in PATH when the command name does not contain a slash. Shell startup files differ by shell and setup, so do not blindly edit .bashrc without checking which shell you use. Inspect the current setting with:

echo "$PATH"
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Fix common errors

Permission denied

Check permissions and add execute permission for the owner:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
ls -l script.sh
chmod u+x script.sh

If it still fails, check ownership and whether the file is on a mounted filesystem with execution disabled, such as some Windows or shared filesystems. You can test the contents with bash script.sh, but that does not fix direct-execution permissions.

command not found

You may have omitted ./, used a misspelled command, or called a program that is not installed or is absent from PATH. Check:

command -v command-name
echo "$PATH"

bad interpreter: No such file or directory

The shebang may point to an unavailable interpreter, or the file may have Windows CRLF line endings. Inspect it with:

head -n 1 script.sh
file script.sh

If the file has Windows line endings, remove carriage returns with:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
sed -i 's/r$//' script.sh

No such file or directory

Check the filename, spelling, location, and current directory:

pwd
ls -l

syntax error

The script may contain Bash syntax but have been run with sh, or it may contain an unmatched quote, bracket, or command substitution. Try:

bash -n script.sh
bash script.sh

The script cannot find its files

Relative paths are based on the caller’s current directory, not necessarily the script’s directory. Use pwd, absolute paths, or the Bash script-directory pattern shown above.

Different behavior with sudo

sudo changes the effective user and may change the home directory, environment, PATH, and ownership of files created by the script. Use it only for the specific operation that genuinely needs elevated privileges. Running the entire script as root is not a general permission fix.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

The script appears to do nothing

Trace it and inspect its exit status:

bash -x script.sh
echo $?

Also check for redirected output, skipped conditional branches, commands waiting for input, and invalid line endings.

Safe shell-script habits

  • Read and understand a script before running it, especially with sudo.
  • Inspect downloaded scripts with less downloaded-script.sh.
  • Pay particular attention to rm, dd, mkfs, recursive chmod or chown, writes to /dev, and changes to /etc, boot files, or package configuration.
  • Avoid blindly pasting commands from untrusted websites.
  • Test unfamiliar scripts in a disposable directory or virtual machine.
  • Quote variables and use "$@" when preserving argument boundaries matters.
  • Use the narrowest permissions necessary, normally chmod u+x.
  • Do not assume set -e makes a script safe; Bash has exceptions to when it exits on errors. Design error handling deliberately, as described in the Bash set reference.

Further reading

The exact Bash features available depend on the Ubuntu release and installed Bash version. Ubuntu’s Noble reference lists Bash package version 5.2.21-2ubuntu4, while the current GNU Bash manual documents Bash 5.3; these are not claims that every Ubuntu installation uses the same version. See the Ubuntu Bash manpage and the GNU Bash manual.

Automatic startup, cron jobs, systemd services, and desktop autostart are separate topics. First make sure the script works manually, has the intended interpreter, and returns a sensible exit status.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.