When automating file transfers via ncftp
in bash scripts, network instability or temporary server issues can cause failures. Unlike human operators who retry manually, scripts need explicit error handling.
The $?
variable stores the exit code of the last executed command:
ncftpput -DD -z -u user -p password server /remote /local/file
echo $? # Prints 0 for success, non-zero for failure
The original approach has syntax issues. Here's a corrected version:
until [ $? -eq 0 ]; do
ncftpput -DD -z -u user -p password server /remote /local/file
done
Basic loops risk infinite retries. Add these improvements:
max_retries=5
retry_count=0
until [ $? -eq 0 ] || [ $retry_count -ge $max_retries ]; do
((retry_count++))
ncftpput -DD -z -u user -p password server /remote /local/file
if [ $? -ne 0 ]; then
echo "Attempt $retry_count failed, retrying in 5 seconds..."
sleep 5
fi
done
[ $retry_count -ge $max_retries ] && echo "Max retries reached" >&2
For production systems, implement progressive delays between retries:
max_retries=8
base_delay=2
max_delay=300
for ((i=1; i<=max_retries; i++)); do
ncftpput -DD -z -u user -p password server /remote /local/file
if [ $? -eq 0 ]; then
echo "Transfer succeeded"
break
fi
delay=$((base_delay ** i))
[ $delay -gt $max_delay ] && delay=$max_delay
echo "Attempt $i failed, retrying in $delay seconds..."
sleep $delay
done
For reusable code across scripts:
retry_command() {
local cmd="$@"
local max_attempts=3
local attempt=1
until $cmd || [ $attempt -ge $max_attempts ]; do
echo "Command failed, retrying..."
((attempt++))
sleep 1
done
return $?
}
retry_command ncftpput -DD -z -u user -p password server /remote /local/file
Differentiate between temporary and permanent failures:
ncftpput -DD -z -u user -p password server /remote /local/file
exit_code=$?
case $exit_code in
0) echo "Success" ;;
1) echo "Usage error - not retryable" >&2 ;;
2) echo "Connection failed - will retry" ;;
*) echo "Unknown error $exit_code" >&2 ;;
esac
When automating file transfers with ncftp, network hiccups or temporary server issues can cause failures. Instead of manually restarting failed transfers, we can create a robust bash script that automatically retries until success.
In bash, every command returns an exit status code. A value of 0 indicates success, while non-zero means failure. We can leverage this in our retry logic.
Here's a simple implementation that keeps retrying until the transfer succeeds:
#!/bin/bash
until ncftpput -DD -z -u user -p password remoteserver /remote/dir /local/file
do
echo "Transfer failed, retrying in 5 seconds..."
sleep 5
done
For production use, we should add several improvements:
#!/bin/bash
MAX_RETRIES=10
RETRY_DELAY=30
RETRY_COUNT=0
until [ $RETRY_COUNT -eq $MAX_RETRIES ] || ncftpput -DD -z -u user -p password remoteserver /remote/dir /local/file
do
((RETRY_COUNT++))
echo "Attempt $RETRY_COUNT failed, waiting $RETRY_DELAY seconds..."
sleep $RETRY_DELAY
done
if [ $RETRY_COUNT -eq $MAX_RETRIES ]
then
echo "Transfer failed after $MAX_RETRIES attempts."
exit 1
else
echo "Transfer completed successfully."
exit 0
fi
We can make the script more sophisticated by checking specific error codes:
#!/bin/bash
MAX_RETRIES=5
RETRY_DELAY=10
for ((i=1; i<=MAX_RETRIES; i++))
do
ncftpput -DD -z -u user -p password remoteserver /remote/dir /local/file
EXIT_CODE=$?
case $EXIT_CODE in
0) echo "Transfer successful"
exit 0
;;
1) echo "Local file error"
exit 1
;;
2) echo "Connection error (retryable)"
sleep $RETRY_DELAY
continue
;;
3) echo "Authentication error"
exit 1
;;
*) echo "Unknown error (retryable)"
sleep $RETRY_DELAY
continue
;;
esac
done
echo "Maximum retries reached"
exit 1
For better handling of persistent issues, we can implement exponential backoff:
#!/bin/bash
MAX_RETRIES=8
INITIAL_DELAY=5
BACKOFF_FACTOR=2
DELAY=$INITIAL_DELAY
for ((i=1; i<=MAX_RETRIES; i++))
do
echo "Attempt $i of $MAX_RETRIES..."
ncftpput -DD -z -u user -p password remoteserver /remote/dir /local/file
if [ $? -eq 0 ]
then
echo "Transfer successful"
exit 0
fi
echo "Waiting $DELAY seconds before retry..."
sleep $DELAY
DELAY=$((DELAY * BACKOFF_FACTOR))
done
echo "Transfer failed after $MAX_RETRIES attempts"
exit 1