start here

Linux Shell Basics for PHP Developers

PHP developers do not need to become full-time system administrators, but they do need enough shell skill to run projects, inspect logs, debug paths, check permissions, and understand automation.

The shell is where many PHP tasks happen: Composer commands, test runners, syntax checks, queue workers, deployment checks, cron jobs, Docker commands, and production diagnostics.

Start with the commands that help you understand where you are and what files exist.

pwd
ls
ls -la
cd /path/to/project
find . -maxdepth 2 -type f -name "*.php"

Useful meanings:

  • pwd prints the current directory
  • ls -la shows hidden files and permissions
  • cd changes directory
  • find locates files by name, type, or path

Before running a PHP command, confirm you are in the project directory you think you are in.

Inspecting Files

Common file-reading commands:

cat composer.json
less storage/logs/app.log
tail -n 50 storage/logs/app.log
tail -f storage/logs/app.log

tail -f follows a log as new lines are written. It is useful while reproducing a web request or running a queue worker.

Searching Code And Logs

Use rg when available because it is fast and respects many ignore files by default.

rg "DB_HOST"
rg "function handle" app
rg "RuntimeException" storage/logs

If rg is not installed, grep is common:

grep -R "DB_HOST" .
grep -R "RuntimeException" storage/logs

Search before guessing. Many configuration, route, service, and error questions can be answered by finding the exact string in the project.

PATH And Active Commands

When you type a command, the shell finds it through PATH.

echo $PATH
which php
which -a php
php -v

For PHP projects, always be ready to prove which php, composer, and framework command you are running.

which composer
composer --version

If the shell runs the wrong binary, application changes will not fix it.

Environment Variables

Environment variables are part of the process environment.

printenv
printenv APP_ENV
APP_ENV=local php -r 'echo getenv("APP_ENV") . PHP_EOL;'

That last command sets APP_ENV only for that single PHP process.

Inside PHP:

PHP example
<?php

declare(strict_types=1);

echo getenv('APP_ENV') ?: 'not set';
echo PHP_EOL;

// Example:
// APP_ENV=local php env.php
//
// Prints:
// local

Shell environment, systemd environment, Docker environment, and web-server environment can all differ.

Pipes And Redirection

Pipes pass output from one command into another.

php -m | sort
php -m | grep mbstring
tail -n 200 storage/logs/app.log | grep ERROR

Redirection writes output to files.

php script.php > output.txt
php script.php 2> errors.txt
php script.php > output.txt 2> errors.txt

Normal output is stdout. Error output is stderr. Good CLI tools keep those separate.

Reading Piped Input In PHP

PHP can read piped input from STDIN.

PHP example
<?php

declare(strict_types=1);

$input = stream_get_contents(STDIN);
$lines = array_filter(explode("\n", trim($input)));

echo 'Lines: ' . count($lines) . PHP_EOL;

// Example:
// printf "one\ntwo\n" | php count-lines.php
//
// Prints:
// Lines: 2

This is useful for small maintenance tools that work with command output.

Permissions And Ownership

Permission issues are common in PHP projects because web servers, queue workers, and shell users may be different users.

whoami
id
ls -la storage
ps aux | grep php-fpm

If PHP cannot write cache, sessions, logs, or uploads, check ownership and permissions before changing application logic.

Avoid blindly running chmod -R 777. It hides the problem and creates security risk.

Processes And Services

You may need to know whether PHP-FPM, a queue worker, or a local server is running.

ps aux | grep php
systemctl status php-fpm
systemctl list-units "php*"

For a local built-in server:

php -S 127.0.0.1:8000 -t public

Stop a foreground process with Ctrl+C.

Exit Codes

The shell tracks whether the last command succeeded.

php -l public/index.php
echo $?

0 means success. Non-zero means failure.

CI jobs, deploy scripts, cron, and shell pipelines depend on exit codes. A PHP script used in automation should exit non-zero when it fails.

What You Should Be Able To Do

After this lesson, you should be able to navigate a project, inspect files, search logs, prove active binaries, read environment variables, use pipes and redirection, understand basic permissions, and check PHP-related processes.

For junior PHP work, this matters because many real bugs are found from the shell first: wrong PHP version, missing extension, bad permissions, failing worker, or an error line in a log.

Practice

Practice: Shell Debugging Checklist

Create a checklist for debugging a PHP project from the Linux shell.

Task

Include commands to:

  • confirm the current directory
  • list files and permissions
  • find PHP files
  • search for an environment variable name
  • show the active PHP binary and version
  • show loaded PHP configuration
  • follow the last lines of an application log

Afterward, add a short note explaining which command you would run first when a project behaves differently from what you expect.

Show solution
pwd
ls -la
find . -maxdepth 2 -type f -name "*.php"
rg "APP_ENV"
which php
php -v
php --ini
tail -n 100 storage/logs/app.log

If rg is not installed:

grep -R "APP_ENV" .

The first command should usually be pwd. If you are in the wrong directory or inside the wrong container, every later result can mislead you.

Task: Pipe Input

Create a small PHP CLI tool that reads lines from STDIN.

Requirements

Build a script that:

  • reads piped input from STDIN
  • counts non-empty lines
  • prints the count to stdout
  • writes an error to STDERR and exits with 1 when no input is provided

Use strict types. Keep example commands and output inside the PHP code block as comments.

Show solution

This script behaves like a small shell-friendly tool.

PHP example
<?php

declare(strict_types=1);

$input = stream_get_contents(STDIN);
$lines = array_values(array_filter(
    explode("\n", trim($input)),
    static fn (string $line): bool => trim($line) !== '',
));

if ($lines === []) {
    fwrite(STDERR, "No input received.\n");
    exit(1);
}

echo 'Non-empty lines: ' . count($lines) . PHP_EOL;
exit(0);

// Example:
// printf "alpha\nbeta\n\n" | php count-lines.php
//
// Prints:
// Non-empty lines: 2
//
// Failure example:
// printf "" | php count-lines.php
//
// STDERR:
// No input received.

This shape works well in automation because stdout contains normal results, stderr contains diagnostic output, and the exit code tells the shell whether the command succeeded.

Task: Debug Paths

Create a checklist for debugging wrong paths and wrong binaries in a PHP project.

Requirements

Include commands to show:

  • current directory
  • active PHP binary
  • all visible PHP binaries
  • active Composer binary
  • PATH entries
  • loaded PHP configuration

Afterward, add a short note explaining why path checks should happen before editing code.

Show solution
pwd
which php
which -a php
php -v
which composer
composer --version
echo $PATH
php --ini

If the project runs in Docker, WSL, or a remote server, run the same checks inside that environment.

Path checks should happen before editing code because the failure may be caused by running the wrong binary, wrong project directory, wrong shell environment, or wrong configuration file. Code changes do not fix those problems.