Create a Raspberry Pi Camera Script That Saves Timestamped Photos

Learn to create, edit, execute, and troubleshoot a Raspberry Pi Bash script that captures JPEG photos with timestamped filenames.

Goal and workflow

A reusable shell script is a text file containing commands that a shell runs in sequence. This lets you automate a camera capture instead of typing every command manually.

In this lesson, you will create a Bash script that captures one JPEG image and stores it in a dedicated folder. The workflow is:

  1. Create an image directory.
  2. Create a Bash script in Nano.
  3. Add a timestamp variable and camera capture command.
  4. Grant the script executable permission.
  5. Run the script.
  6. Verify that the timestamped JPEG was saved.

A timestamp is a date-and-time value that identifies when something happened. Including one in each filename prevents later photos from routinely overwriting earlier photos. The basic example records time to the minute; a seconds-based format is shown later for faster repeated captures.

Prerequisites and camera software

You need a Raspberry Pi with a supported camera module connected correctly, Raspberry Pi OS, and access to a terminal. Basic knowledge of Linux directories, paths, Nano, and file permissions is helpful.

Raspbian is the former name of Raspberry Pi OS. This lesson uses the legacy raspistill command, which belongs to older Raspberry Pi camera software stacks and captures still images.

Current Raspberry Pi OS releases commonly use newer camera tooling instead of raspistill. If your system reports that raspistill is unavailable, identify the camera software stack and use the still-image command supported by that environment. The Bash concepts remain the same: create a timestamp, construct an output path, run the camera command, set permissions, and verify the file.

Create the image storage folder

Open a terminal and create a folder named pics in the home directory of the user named pi:

mkdir /home/pi/pics

mkdir means “make directory.” The path /home/pi/pics is an absolute path: it begins with / and identifies the complete location from the filesystem root.

If your account is not named pi, replace /home/pi with your actual home directory. You can display the current home directory with:

echo $HOME

For example, if the result is /home/alex, use /home/alex/pics in the commands and script. Confirm that the folder exists and inspect its permissions:

ls -ld /home/pi/pics

The current user should own the directory or otherwise have write permission. You can also test writing to it:

touch /home/pi/pics/write-test.txt
rm /home/pi/pics/write-test.txt

If both commands complete without an error, the user can write to the folder.

Create the Bash script in Nano

Use nano, a terminal-based text editor, to create a script with a descriptive name and the .sh extension:

nano /home/pi/take-picture.sh

The first line must be the shebang:

#!/bin/bash

A shebang is the first line of an executable script. It tells the operating system which interpreter should read the file. Here, /bin/bash identifies Bash, a command interpreter and scripting language used to automate Linux tasks.

Enter this legacy raspistill version:

#!/bin/bash
DATE=$(date +%Y-%m-%d_%H%M)
raspistill -vf -hf -o /home/pi/pics/$DATE.jpg

In Nano, save with Ctrl+O, press Enter to accept the filename, and exit with Ctrl+X. Check that the file was saved at /home/pi/take-picture.sh.

Understand the timestamp filename

The second line uses command substitution:

DATE=$(date +%Y-%m-%d_%H%M)

Command substitution uses $(...) to run a command and insert its output. The date command produces the current date and time. That output is assigned to the variable named DATE. A variable is a named value that a script can store and reuse.

The format string produces values such as 2026-08-18_1437. The value is then used in the output path:

/home/pi/pics/$DATE.jpg

Consequently, a captured file might be named /home/pi/pics/2026-08-18_1437.jpg. The underscores and hyphens are safe filename characters and make the name easy to read and sort.

Format tokenOutput componentExample value
%YFour-digit year2026
%mTwo-digit month08
%dTwo-digit day18
%HHour in 24-hour format14
%MMinute37
%SSeconds42

The basic format ends at %M, so two captures in the same minute can receive the same filename. In that situation, the later capture may replace the earlier one. For more unique names, include seconds:

DATE=$(date +%Y-%m-%d_%H%M%S)

This could produce 2026-08-18_143742.jpg. Seconds reduce collisions for rapid captures. Very rapid or concurrent captures may need an additional unique suffix strategy.

Capture the photo

This command captures a still image and writes it to the path after the -o option:

raspistill -vf -hf -o /home/pi/pics/$DATE.jpg

The output path combines the pictures directory, the value stored in DATE, and the .jpg extension. JPEG is a common compressed image format, and .jpg is a common extension for it.

The options -vf and -hf mean vertical flip and horizontal flip. They are included when the physical mounting orientation makes the result upside down or mirrored. Compare a test image with the real scene:

  • Remove -vf if vertical flipping is not needed.
  • Remove -hf if horizontal flipping is not needed.
  • Remove both options when the image orientation is already correct.
  • Keep one or both options when the camera mounting requires them.

Make the script executable

Run:

chmod +x /home/pi/take-picture.sh

chmod changes file permissions. The +x option adds executable permission, which allows the file to be launched directly as a program.

Inspect the permissions with:

ls -l /home/pi/take-picture.sh

Look for an x in the permission listing, such as -rwxr-xr-x. If the script is not executable, repeat the chmod +x command.

Run and verify the script

You can run an executable script by using its full path:

/home/pi/take-picture.sh

A full path works from any current directory. If you first change to the directory containing the script, use ./:

cd /home/pi
./take-picture.sh

The prefix ./ means “the file in the current directory.” Linux usually does not search the current directory when a command is entered without a path, so typing only take-picture.sh may fail.

You can also explicitly ask Bash to interpret the file:

bash /home/pi/take-picture.sh

Invoking it through bash does not require the executable bit, although the shebang remains good practice and direct execution still requires chmod +x.

After running the script, list the destination folder:

ls -l /home/pi/pics

You should see a JPEG whose name contains the capture date and time, for example 2026-08-18_1437.jpg. Open the file from the desktop or use the file manager to confirm that it contains the expected camera image.

Command or syntaxPurposeKey notes
mkdirCreate a directoryUse an absolute destination path when you want a predictable location.
nanoEdit or create a text fileSave with Ctrl+O; exit with Ctrl+X.
dateGenerate the current date and timeFormat it with tokens such as %Y and %M.
raspistillCapture a legacy still imageIt may be unavailable on current camera software stacks.
chmod +xAdd executable permissionRequired for direct execution.
Full pathRun a script from any directoryExample: /home/pi/take-picture.sh.
./Run a script from the current directoryExample: ./take-picture.sh.

Run the script from the desktop file manager

An executable script can also be launched through the graphical file manager. Browse to the script, select it, and choose the execute or run option when the file manager prompts you. The exact wording depends on the desktop configuration.

Graphical execution can make terminal errors less visible. For example, a missing camera command or a permission error may appear only briefly or not be obvious. Run the script from a terminal first when testing or diagnosing problems. Once it works reliably, the file manager provides a convenient graphical launch method.

Troubleshooting

SymptomLikely causeResolution
Camera command unavailableThe system uses a newer camera software stack, or legacy camera software is not installed or enabled.Confirm the Raspberry Pi OS and camera stack. Use the supported still-image command while retaining the script's timestamp and output-path structure.
No image savedThe destination directory does not exist, the -o path is wrong, or the user cannot write there.Run ls -ld /home/pi/pics, check the output path, test write access, and run the script in a terminal to read errors.
Permission deniedThe executable bit is missing or the destination is not writable.Run chmod +x /home/pi/take-picture.sh and check directory ownership and permissions.
Image upside down or mirroredThe camera module is mounted in a different orientation.Test -vf and -hf; remove either or both when unnecessary.
Repeated filename overwrites an imageThe timestamp records only to the minute and captures occurred within the same minute.Add %S to the date format. For extremely rapid captures, add another unique suffix strategy.

The script cannot be run directly

  • Apply executable permission with chmod +x.
  • Use the full path or prefix the filename with ./.
  • Check that the first line is exactly #!/bin/bash.
  • Save the file as Unix text. Incorrect line endings can make a valid shebang fail.

The image is missing from the expected folder

Check the directory first:

ls -ld /home/pi/pics
ls -l /home/pi/pics

Then inspect the script's -o option. The destination should contain the directory, variable, and extension, such as /home/pi/pics/$DATE.jpg. Running from a terminal is useful because camera and filesystem errors remain visible.

Complete example

This is the complete minute-based legacy example:

#!/bin/bash
DATE=$(date +%Y-%m-%d_%H%M)
raspistill -vf -hf -o /home/pi/pics/$DATE.jpg

For captures that may occur seconds apart, use:

#!/bin/bash
DATE=$(date +%Y-%m-%d_%H%M%S)
raspistill -vf -hf -o /home/pi/pics/$DATE.jpg

The essential pattern is reusable even when the camera command changes: calculate a filename, provide the destination to the camera tool, make the script executable, run it, and inspect the resulting JPEG. Continue with the Raspberry Pi picture script lesson when you need to revisit the workflow.