How To Run A Shell Script In Linux

How To Run A Shell Script In Linux

Reading time1 min
#Linux#Shell#Scripting#Permissions#Bash#LinuxShell

Mastering Permissions: The Essential Step to Run Shell Scripts Seamlessly in Linux

Shell scripts fail for many reasons; permission errors are by far the most common. A simple test:

$ cat > backup.sh <<EOF
#!/bin/bash
echo "Starting backup..."
# rsync commands would go here
echo "Backup completed."
EOF

$ ./backup.sh
bash: ./backup.sh: Permission denied

No syntax errors, no path mishaps—just a missing permission bit. File permissions are not optional in Linux; they are mandatory, enforced by the kernel, and rooted in UNIX isolation models. Ignoring them leads to operational headaches, from deployment outages to accidental privilege escalation.


Anatomy of Permissions (and Their Impact)

Linux enforces three permission sets per file: owner, group, and others. Typical output from ls -l backup.sh after file creation:

-rw-r--r-- 1 ops ops 73 Jun 10 10:30 backup.sh
Permission BlockMeaningDefault from touch
rReadAlways present
wWriteOwner (and sometimes group)
xExecuteMissing by default

No execute bit, no execution. This is not a safety net—it’s core design.


Granting Execution Rights

The fix is unambiguous:

chmod u+x backup.sh

Afterward, inspect changes:

-rwxr--r-- 1 ops ops 73 Jun 10 10:31 backup.sh

Owner can now execute. If a CI pipeline uses a specific service account or group identity, set the group bit as well:

chmod ug+x backup.sh

In tightly regulated environments (PCI, HIPAA), never use chmod 777. Over-broad permissions weaken auditing and increase attack surface.


Running the Script: Interpreter versus Direct Execution

Direct execution honors the #! (shebang) line, invoking the intended interpreter:

./backup.sh

No execute permission? The kernel blocks execution:

bash: ./backup.sh: Permission denied

Calling the interpreter explicitly bypasses this:

bash backup.sh

But this approach sidesteps the shebang—problematic if the script targets another shell or a non-POSIX environment (e.g., #!/bin/sh, #!/usr/bin/env bash, or even Python). Avoid in production unless necessary.


Side Notes from Production

  • Scripts in /tmp: Some hardened systems mount /tmp with noexec. Even with chmod +x, execution fails.

    bash: ./backup.sh: Permission denied
    # But file permissions may show as executable
    
  • ACLs and SELinux/AppArmor: Standard UNIX permissions are not the whole story. If a script runs fine on one system but fails on another, check access control lists or mandatory access controls (ls -Z, getfacl).

  • File Synchronization Quirks: Transferring via Windows SMB or certain SCP/FTP tools can strip execute bits. Always verify after file transfer.


Non-Obvious Practice: Auditing with stat

ls -l shows permissions, but stat is more granular:

stat backup.sh

Relevant output segment:

Access: (0744/-rwxr--r--)  Uid: ( 1001/   ops)   Gid: ( 1001/   ops)

Consistent permissions are critical in multi-user or CI/CD-controlled environments.


Secure Defaults and Hardening

For scripts with sensitive operations (e.g., containing AWS credentials, DB maintenance tasks), restrict access:

chmod 700 deploy.sh

No group or other access. For shared teams, consider chmod 750 with a dedicated script-execution group.


Summary Table: Common Permission Scenarios

Use CaseCommandResult
Personal scriptschmod 700 script.shOnly you: r/w/x
Dev team sharechmod 750 script.shOwner + group: r/w/x
Wide execution (risky)chmod 755 script.shAnyone: read and execute (not write)

Practical Example: Handling "Permission Denied"

Error log:

error: command failed: Permission denied

Workflow to resolve:

  1. Inspect permissions:
    ls -l script.sh
    
  2. Grant execute bit:
    chmod u+x script.sh
    
  3. Test direct invocation:
    ./script.sh
    

If running within cron, remember: the environment is minimal. Use absolute paths, and ensure permissions are set prior to scheduling.


Takeaways

  • Default script files lack execute permission. Always review (ls -l) and explicitly set execute bits as needed.
  • Execution method matters: direct (./script.sh) respects permissions; interpreter invocation (bash script.sh) ignores them but bypasses shebang logic.
  • Harden permission settings for production. Validate via stat in build or deployment pipelines.
  • Don’t trust transferred files; reassert permissions after sync or upload.

There are alternative approaches—ACLs, sudoers, and containerized runners—but proper use of classic UNIX permissions remains the foundational defense and enabler for reliable script execution.