Linux / Bash

Bash Script Hangs Waiting for Input in Cron

A script that runs perfectly when you execute it manually but hangs forever under cron almost always means something in the script is waiting for interactive input — a prompt, a confirmation, a password — which works fine when you're sitting at the terminal to answer it, but blocks indefinitely when cron runs it with no one there to respond.

The Problem

A cron job never completes and never produces output, unlike a script that fails quickly with an error. Checking running processes shows the script's process still alive, sometimes hours after it should have finished:

ps aux | grep your_script.sh
user  12345  0.0  0.1  ...  your_script.sh

The exact same script run manually from a terminal completes normally.

Why It Happens

Several common commands and patterns silently wait for input that a human would normally provide interactively, and these all behave differently under cron, which has no terminal attached at all:

  • A command that prompts for confirmation (like some package managers or destructive operations) waiting for a y/n answer that never comes
  • An ssh or scp command that needs a password, or is connecting to a host for the first time and waiting on a host key confirmation prompt
  • A command reading from stdin explicitly (read in Bash, or a tool designed to accept piped input) with nothing actually piped in under cron, so it waits for input that will never arrive
  • A sudo command that requires a password and isn't configured for passwordless execution in this specific context, silently waiting at the password prompt

The Fix

First, identify exactly which command in the script is responsible for the hang. Since cron gives no interactive feedback, temporarily run the script with output redirected to a log file, and check what the last logged action was before it stalled:

0 2 * * * /path/to/script.sh >> /path/to/log.txt 2>&1

The last line written to the log, right before the hang, usually points directly at the blocking command.

For SSH connections, avoid interactive host key prompts by pre-adding the host to known_hosts before the cron job ever runs, or by explicitly disabling strict host key checking for automated, trusted contexts:

ssh -o StrictHostKeyChecking=no -o BatchMode=yes user@host

BatchMode=yes specifically tells SSH to never prompt for anything interactively, failing immediately with an error instead of hanging if authentication can't proceed automatically — this converts a silent hang into a visible, debuggable failure, which is a meaningful improvement even before addressing the underlying authentication setup.

For SSH authentication itself, set up key-based authentication rather than relying on password prompts, since a password prompt has no way to be answered non-interactively at all:

ssh-copy-id user@host

For commands that might prompt for confirmation, check if they support a flag to skip confirmation prompts explicitly (commonly -y, --yes, or --non-interactive, depending on the specific tool):

apt-get install -y package-name

For sudo commands specifically requiring elevated privileges under cron, configure passwordless sudo for that specific command in /etc/sudoers, rather than relying on an interactive password prompt that cron has no way to answer:

# /etc/sudoers.d/cron-script
your_user ALL=(ALL) NOPASSWD: /path/to/specific/command

Scope this as narrowly as possible to the specific command needed, rather than granting broad passwordless sudo access, to avoid introducing an unnecessary security risk for the sake of convenience.

Still Not Working?

If you've addressed the obvious candidates above and the script still hangs without a clear cause, redirect stdin explicitly to /dev/null for the entire script invocation under cron. This guarantees that any command attempting to read from stdin fails immediately rather than blocking indefinitely, converting a silent, invisible hang into an explicit, loggable error that points you directly at the actual problematic command:

0 2 * * * /path/to/script.sh < /dev/null >> /path/to/log.txt 2>&1