The Handbook

    Theme
    • Guides
        • Check a system before installing FreeBSD
        • Orient a Linux administrator on FreeBSD
        • Supported FreeBSD releases
        • Choose a FreeBSD documentation and support channel
        • Move files safely without GNU mv -t
        • Update and Upgrade FreeBSD
        • Upgrade 14.4 or 15.0 to FreeBSD 15.1
        • Choose packages, ports, or poudriere
        • Choose the quarterly or latest package branch
        • Choose a FreeBSD download or package mirror
        • Make a system setting persistent
        • Run a command from cron reliably
        • Configure locale, keyboard, and time zone
        • Configure a serial console for recovery
        • Choose a custom kernel, module, or loader setting
        • Run a Linux binary with the compatibility layer
        • Check desktop and laptop hardware before installation
        • Choose and check a graphics driver
        • Choose Xorg or Wayland
        • Build a maintainable desktop baseline
        • Install and check a desktop browser
        • Check laptop Wi-Fi, power, and suspend
        • Check multimedia readiness
        • Choose and configure a printing stack
        • Run Windows applications with Wine
        • Snapshot and replicate a ZFS dataset
        • Choose a filesystem and storage layout
        • Operate ZFS without losing the recovery path
        • Restore files from a ZFS snapshot
        • Find what is using ZFS space
        • Grow a ZFS virtual disk
        • Read ZFS pool health and run a scrub
        • Replace a failed device in a ZFS mirror
        • Replicate a ZFS dataset over SSH
        • Change PF safely on a remote host
        • Configure a narrow WireGuard tunnel
        • Share a directory with NFS
        • Share files with a named Samba account
        • Plan a FreeBSD home server
        • Choose a mail server or an outgoing relay
        • Publish a network service safely
        • Choose a jail network model
        • Choose native jails or a jail manager
        • Choose a jail or a bhyve virtual machine
        • Establish a FreeBSD security baseline
        • Choose a MAC policy
        • Audit security-relevant activity
        • Start a DTrace performance investigation
    • Integrations
        • Create a first jail with Bastille
        • Compare jail managers and OCI tooling
        • Publish a Bastille service through PF
        • Mount a ZFS dataset in a Bastille jail
        • Update and upgrade Bastille jails
        • Back up and restore a Bastille jail
        • Prepare bhyve and vm-bhyve
        • Choose NFS or Samba for file sharing
        • Choose ZFS backup automation
        • Build a first signed poudriere repository
        • Operate a signed poudriere repository
        • Manage FreeBSD configuration with Ansible or Salt
        • Run Motion with webcamd on FreeBSD
        • Design a reverse proxy, certificates, and monitoring
    • FAQ
      • Troubleshooting
          • Recover an interrupted freebsd-update run
          • Resolve a package repository or ABI mismatch
          • Diagnose the FreeBSD boot path
          • Recover with a ZFS boot environment
          • Diagnose DNS, routing, and firewall paths
          • Diagnose network mbuf exhaustion
          • Bind a service to a low port without running it as root
          • Diagnose a service that will not start
          • Diagnose audio output or input
          • Diagnose webcamd, cuse, and a webcam
          • Fix USB device permissions without opening every device
      • About this handbook
      • Synopsis
      • Prepare a command that works without a terminal
      • Add a per-account crontab entry
      • Verify the scheduled result
      • Choose the final schedule
      • Primary references

      Run a command from cron reliably

      Last reviewed
      7 November 2026
      Applies to
      15.1-RELEASE
      Tested on
      15.1-RELEASE

      Synopsis #

      A command that works in a terminal can fail under cron because it runs as another account, depends on shell startup files, uses relative paths, or expects an interactive prompt. Put the operation in a small script, run it as the intended account, and capture its output before choosing the final schedule.

      The example records the date and home-filesystem space. Replace /home/alice with the intended account’s actual home directory throughout. Run the unprivileged commands as that account.

      Prepare a command that works without a terminal #

      Create a private script directory if necessary:

      $ mkdir -p "$HOME/bin"
      

      Save this as $HOME/bin/record-status:

      #!/bin/sh
      set -eu
      PATH=/bin:/usr/bin
      export PATH
      cd /home/alice
      /bin/date -u
      /bin/df -h /home/alice
      

      Make it executable and test with an explicit environment:

      $ chmod 0755 "$HOME/bin/record-status"
      $ env -i HOME="$HOME" PATH=/bin:/usr/bin SHELL=/bin/sh /bin/sh "$HOME/bin/record-status"
      

      This is a useful environment check, but the scheduled run remains the final test. Add /usr/local/bin or /usr/local/sbin to the script’s PATH when it uses packaged commands. Password prompts, graphical sessions, and interactive shell aliases are unsuitable dependencies for an unattended job.

      Add a per-account crontab entry #

      Inspect the existing schedule, then edit it:

      $ crontab -l
      $ crontab -e
      

      no crontab for ... means that no per-account table exists yet. Preserve existing entries. Add this temporary once-per-minute check, ending the line with a newline:

      * * * * * /home/alice/bin/record-status >> /home/alice/status.log 2>&1
      

      A per-account entry has five time fields followed by the command. Do not insert a username between the schedule and command. /etc/crontab and files under /etc/cron.d or /usr/local/etc/cron.d use the different system format, which includes that username field.

      Confirm the saved entry:

      $ crontab -l
      

      The daemon notices changes made by crontab; restarting cron is unnecessary.

      Verify the scheduled result #

      After the next minute boundary, inspect the output:

      $ tail -n 20 "$HOME/status.log"
      

      The file should contain a new date and filesystem report. Check its owner and the command’s result, rather than treating installation of a crontab as proof that the job ran.

      If nothing appears, an administrator can check the daemon and its log:

      # service cron status
      # tail -n 50 /var/log/cron
      

      Check that the account is usable, the script is executable, its interpreter exists, and the account can read its inputs and write the log. Cron uses /bin/sh for the command line by default; it does not run an interactive login shell. An unescaped % in the command field also has special meaning in crontab(5), even inside shell quotes. Put commands using date format strings in the script instead.

      Choose the final schedule #

      Use crontab -e to replace the temporary entry with the intended frequency, or remove that entry after testing. Do not use crontab -r to remove one job: it removes the account’s entire table.

      Redirecting output to a file requires a rotation or retention plan. Without redirection, cron normally mails command output; that is useful only when local operational mail reaches a monitored mailbox. See Choose a mail server or an outgoing relay .

      Primary references #

      • crontab(1)
      • crontab(5)
      • cron(8)
      • FreeBSD Handbook: Cron and Periodic

      Independent documentation. Not affiliated with or endorsed by the FreeBSD Project or the FreeBSD Foundation.

      Report a bug
      • Synopsis
      • Prepare a command that works without a terminal
      • Add a per-account crontab entry
      • Verify the scheduled result
      • Choose the final schedule
      • Primary references