Home › Topics › CLI Clients › One-Liners

A Transfer One-Liner Cookbook

Some knowledge you look up; some you carry. The dozen commands in this cookbook belong in the carried category. There is the upload, the download, the mirror, the newest-file grab, the cleanup — one memorable line each. They span the clients that are actually installed on the systems you manage. Between them they cover most of what an administrator moves in a normal week, with nothing but what the machine already has.

This is the closing article of our command-line client mastery series, and it is deliberately honest about what a one-liner is: a starting point. Each recipe below states when to use it and what its flags do. The article ends with the graduation rule — the specific signs that a line has earned promotion into a real script, or past scripts entirely. Memorize the recipes; respect the rule.

How to Read These Recipes

Three conventions keep the recipes short. First, hostnames and paths are placeholders — substitute your own. Second, credentials never appear on the command line. The sftp and scp recipes assume key authentication is set up and the server's host key is already accepted. That setup is walked through in the sftp client, mastered. The curl recipes assume a ~/.netrc file with locked-down permissions holds any FTP or FTPS logins. If a recipe "works" only after you paste a password into it, stop and fix the credential setup first. A password in a command line is visible in the process list and preserved in shell history.

Third, rehearse against a server you own before pointing anything at a partner. If you do not have a spare, a trial of Sysax Multi Server from the download page gives you a Windows server in a few minutes. It speaks SFTP, FTPS, FTP, and HTTPS. It is a safe place for every recipe here, including the ones that delete things.

Which Client for Which Job

The diagram below is the thirty-second version of this whole series: match the job's needs to the client whose strengths they are.

Decision diagram for choosing a transfer client. A job needing one known file now points to sftp or scp; a one-shot scheduled transfer with retries points to curl; directory trees, mirrors, and parallel transfers point to lftp; jobs needing alerts, audit trails, and workflows point past one-liners to a script or automation tool.

There are two refinements the picture cannot hold. On Windows hosts, curl is present by default while lftp is not, which often decides the question for you. And when both endpoints are machines you hold SSH access to (no transfer server involved), scp and sftp compete with rsync. That comparison is settled in how scp works and its companions.

The same decision, in table form, mapped to the recipes below:

The job Reach for Why
Prove a new account works sftp — recipe 1 Tests credentials, host key, and path with an honest exit code
One file, known name, keys in place sftp — recipes 2, 5 Zero ceremony; installed everywhere OpenSSH is
Scheduled single transfer, FTPS, resume curl — recipes 3, 6, 7, 8 Retry flags, resume, required TLS, documented exit codes
Whole trees, changing names, flaky links lftp — recipes 4, 9, 10, 11 mirror, sortable listings, wildcard operations, built-in retries
Two SSH machines, no server between scp — recipe 12 Fastest point-to-point copy in the toolbox
Alerts, audit trails, multi-step workflow None of the above Graduate: a real script, or an automation product

Download Recipes

Four ways to bring files toward you, ordered from the trivial to the honestly-stretching.

1. Prove the login works — sftp

printf 'pwd\nls -l\n' | sftp -b - -o BatchMode=yes deploy@sftp.partner.example

When to use: a partner says "the account is ready" and you want proof — credentials, host key, and starting directory. You want it in ten seconds from the machine that will run the job. -b - reads the piped commands as a real batch (abort on error, honest exit code), and BatchMode=yes turns any would-be prompt into a clean failure you can see.

2. Fetch one known file — sftp

sftp deploy@sftp.partner.example:/outgoing/report.csv /data/inbox/

When to use: the everyday grab — you know the file, you have keys, you want it here. Naming a remote file on the command line makes sftp download it and exit; no session, no batch file, exit code 0 only on success. Point it at a remote directory with -r in front and the whole tree comes down. Add -P for a nonstandard port and -p to keep the original timestamps, which downstream newest-file logic will thank you for.

3. Big download that survives a bad network — curl

curl -sS --netrc -C - --retry 5 --retry-delay 30 \
     -o /data/inbox/archive.tar.gz ftp://ftp.partner.example/outgoing/archive.tar.gz

When to use: a multi-gigabyte file over a link that drops. -C - resumes from wherever the last attempt died instead of starting over. --retry 5 --retry-delay 30 re-tries transient failures on a fixed cadence. -sS keeps the log quiet except for real errors. Add --ssl-reqd when the server speaks FTPS, and --connect-timeout 15 so a dead host fails in seconds. Resist the tempting --retry-all-errors: it re-tries permanent failures too, and five enthusiastic attempts at a wrong password is how partner accounts get locked.

4. Grab the newest file — lftp plus a little shell

f=$(lftp -c 'open sftp://transfer@sftp.partner.example; cls -1 -t /outgoing/*.csv' | head -1) \
  && lftp -c "open sftp://transfer@sftp.partner.example; get -O /data/inbox $f"

When to use: "always fetch the latest export" flows where the name changes daily. cls -1 -t lists bare names newest-first, head -1 keeps the winner, and the second command fetches it into /data/inbox (-O names the destination directory). This is honestly the edge of one-liner territory — two connections, and it breaks on filenames with spaces — which makes it a fine candidate for early graduation. Note the quoting: the second command string uses double quotes precisely so the shell can substitute $f into it. That is the expansion-on-purpose pattern from the heredoc article, compressed to one line.

Upload Recipes

Four ways to send files outward — including the two patterns, streaming and atomic publishing, that separate tidy flows from ticket-generating ones.

5. Push one file — sftp

printf 'put /data/out/results.csv /incoming/\n' | sftp -b - -o BatchMode=yes deploy@sftp.partner.example

When to use: the mirror image of recipe 1 — a keyed, prompt-free push whose exit code a script can trust. The same pipe carries more lines when the job grows: add a rename after the put and you have atomic publishing (recipe 8 shows the curl version). Because -b - aborts at the first failure, the line composes safely with shell logic — ... || alert_someone actually fires when the push fails.

6. Scheduled upload over FTPS — curl

curl -sS --netrc --ssl-reqd --ftp-create-dirs \
     -T /data/out/daily.csv ftp://ftp.partner.example/incoming/

When to use: the workhorse nightly push. -T uploads, and the trailing slash keeps the local filename. --ssl-reqd makes encryption mandatory rather than polite. --ftp-create-dirs builds missing remote directories instead of failing on the first of the month. On Windows hosts the same line works with the bundled curl — just remember the netrc file is named _netrc there. For implicit-FTPS servers, swap the scheme to ftps:// instead of adding the flag.

7. Stream a backup with no temp file — curl

tar czf - /srv/site | curl -sS --netrc -T - \
     "ftp://backup.example.com/backups/site_$(date +%Y%m%d).tar.gz"

When to use: archiving a directory to a server when local disk has no room for the archive itself. tar writes the compressed stream to standard output. -T - uploads straight from the pipe, and the shell stamps the name with today's date. Nothing ever lands on local disk. The honest cost of streaming: there is no local copy to compare afterward. So verify the upload by size or checksum before you trust it. That discipline is described in verifying transfers end to end.

8. Publish atomically — curl

curl -sS --netrc --ssl-reqd -T /data/out/daily.csv \
     ftp://ftp.partner.example/incoming/daily.csv.part \
     -Q "-RNFR incoming/daily.csv.part" -Q "-RNTO incoming/daily.csv"

When to use: whenever something on the far side watches the folder. The file uploads under a .part name, then the two quoted commands rename it server-side after the transfer completes — so no consumer ever reads a half-written file. If a recipe in this cookbook prevents an incident this quarter, it is this one. The sftp equivalent is a two-line batch (put then rename, as in recipe 5's extension). One caveat either way: some servers refuse to rename over an existing file. So delete or rotate the previous day's copy first if your flow reuses names.

Mirror Recipes

Two directions of the same idea: make one tree look like the other, moving only the difference.

9. Keep a local copy of a remote tree — lftp

lftp -c 'open sftp://transfer@sftp.partner.example; mirror --only-newer --verbose /outgoing/reports /srv/inbox/reports'

When to use: a partner maintains a folder of reports and you want yesterday's and today's without re-downloading last year's. mirror compares the trees and moves only what is new or changed; --verbose makes the log say exactly what it did. Put this line on a schedule and you have a working sync job; add --parallel=4 when the tree holds many small files and the nightly window feels tight.

10. Publish a tree upward — lftp

lftp -c 'open sftp://transfer@web.example.com; mirror -R --only-newer --dry-run /var/www/site /htdocs/site'

When to use: pushing a built site or document set to a server. -R reverses the mirror (local to remote), and --dry-run prints the plan without transferring — run it that way first, read the plan, then drop the flag. The full option set, including the respect that --delete demands, is in the lftp article. And --delete is exactly why the dry-run habit matters. A reversed or mistargeted mirror with deletion enabled destroys data at full speed.

Housekeeping Recipes

Transfers are half the job; the other half is leaving both ends tidy.

11. Prune old datestamped archives — lftp

lftp -c "open sftp://transfer@backup.example.com; mrm backups/site_$(date -d '-2 months' +%Y%m)*.tar.gz"

When to use: monthly cleanup where names carry their dates (site_YYYYMMDD.tar.gz). The shell computes the month to purge (GNU date's -d does the arithmetic), and mrm — lftp's wildcard remove — deletes that month's set. Honesty required: this prunes a month per run, not "everything older than N days". True age-based retention needs a listing, a comparison, and a loop. That is a script's job, and precisely the kind of policy a retention-aware tool handles as configuration. Preview before you purge: run the identical glob through cls first and read the list mrm is about to act on.

12. Copy between two SSH machines — scp

scp -i ~/.ssh/transfer_key /data/out/results.csv deploy@app.example.com:/srv/inbox/

When to use: no transfer server in sight — just two machines you hold SSH access to and one file that needs to be on the other one. It is the fastest ceremony-free copy in the toolbox; its honest limits (no resume, minimal semantics) are cataloged in scp's limitations. Like sftp, scp uses capital -P for the port and -r for whole directories, and it inherits every alias and key you have set in ~/.ssh/config.

Making a Recipe Job-Ready

Every recipe above assumes a human at the keyboard who notices failure. The first promotion — the moment a line gets a schedule — costs about four lines of wrapper, and they are the same four for every recipe here:

#!/bin/sh
LOG=/var/log/transfers/pull_reports.log
if ! lftp -c 'open sftp://transfer@sftp.partner.example; mirror --only-newer --verbose /outgoing/reports /srv/inbox/reports' >> "$LOG" 2>&1
then
    echo "pull_reports FAILED" >> "$LOG"
    exit 1
fi

The recipe is unchanged in the middle. Around it, output is captured with errors folded in, the exit code is checked, and failure is recorded and propagated so the scheduler can see it. That is the minimum uniform a one-liner wears before running unattended. Because every client in this cookbook returns honest exit codes, the same wrapper shape works for all twelve recipes. Scheduling it properly, under a service account with its own keys and credentials, is the subject of our scheduled jobs series.

The Legacy Line You Should Recognize

One non-recipe belongs in every administrator's reading vocabulary: ftp -n -i -s:commands.txt. That is the old Windows console ftp client running a command file — no encryption available, no abort on failure, and an exit code of 0 no matter what happened. Do not write it new; do learn to spot it, because it still lurks in inherited scheduled tasks. The built-in ftp clients article covers reading and retiring these jobs. That includes the low-disruption path of swapping in sysaxftp.exe, the drop-in secure replacement client that ships with Sysax FTP Automation. That way, the old batch-file shape survives while the protocol underneath becomes SFTP or FTPS.

The Graduation Rule

Every recipe above is one trustworthy line — and one line is exactly as much reliability as it looks like. The rule that keeps a toolbox honest: the moment a one-liner earns a schedule, it earns a script; the moment the script becomes infrastructure, it earns real automation. Concretely, promote a one-liner into a script — with logging, exit-code checks, and version control — when any of these appear:

  • It runs unattended (cron, Task Scheduler) rather than under your eyes.
  • It needs conditions: only if the file exists, only after the settle check, only on weekdays.
  • It needs a record: someone will ask next week what transferred and when.
  • It needs retry policy smarter than a flat count — backoff, budgets, give-up alerts.
  • Someone else must run or maintain it. A one-liner in your head is a bus-factor of one.

The scripting rung is covered by our bash and cron automation series and the batch modes and command files article. The retry design that scripts inherit is in retry and error handling. And the second promotion comes when a script accumulates schedules, folder watching, encryption, notifications, and an audit trail. That is where a purpose-built product replaces a growing pile of shell. Sysax FTP Automation provides exactly that layer, with wizard-built scheduled tasks, folder monitoring, OpenPGP encryption, and email alerts on failure. The whole progression, rung by rung, is mapped in our automation ladder series.

Rule of thumb: a one-liner is for a human at a keyboard. The first time nobody is watching it run, wrap it in a script that logs and checks its exit code. When that script starts sprouting features, move the flow to real automation before it becomes the undocumented system everything depends on.

Carry the Dozen

Twelve lines cover the work. Prove the login, fetch the known file, survive the bad network, and grab the newest. Push one file, push on a schedule with required encryption, stream a backup, and publish atomically. Mirror down, mirror up, prune by datestamp, and copy machine-to-machine. Learn them until they type themselves — they are the daily currency of transfer work. Every one of them reports failure honestly, which is more than the tools they replaced could say.

If a recipe raised questions, its home article has the depth. Read sftp mastered for recipes 1, 2, and 5, and lftp for 4 and 9 through 11. The curl recipes' HTTP-side cousins live in the curl and wget cookbook.

Frequently Asked Questions

Why does a one-liner that works in my terminal fail in cron?
Cron runs with a minimal environment: a short PATH, a different home directory if the job runs as a service account, and therefore different SSH keys and known_hosts. Use absolute paths for commands and files, name the key explicitly with -i, and test as the account cron will use.
How do I use these recipes without putting passwords in the command?
Set up key authentication for the sftp, lftp-over-SFTP, and scp recipes, and a permission-locked netrc file for curl's FTP and FTPS logins. Passwords typed into command lines end up in the process list and shell history, which is why no recipe here contains one.
Which client should I learn first?
The sftp client — it is installed everywhere OpenSSH is, it covers interactive and batch work, and its key-plus-known-hosts setup is reused by lftp and scp. Add curl for one-shot scheduled jobs and FTPS, then lftp when you need mirroring and retries.
Can I do "delete files older than 30 days" as a one-liner?
Not honestly. Remote clients cannot ask the server for files by age in one step, so real retention needs a listing, a date comparison, and a loop — a small script. The one-liner version works only when names carry their dates and you prune by computed prefix, as in recipe 11.
Do these recipes work on Windows?
Most do: current Windows builds include both the OpenSSH clients (sftp, scp) and curl. So recipes 1 through 3, 5 through 8, and 12 run in a normal command prompt or PowerShell session. The lftp recipes need a Unix-like environment such as the Windows Subsystem for Linux, since lftp has no native Windows build.
When exactly should a one-liner become a script?
The first time it runs without you watching, needs a condition or a retry policy, or must be runnable by someone else. At that point wrap it with logging and exit-code checks, and put it in version control. If it keeps growing, move the flow to a dedicated automation tool.

From the Sysax team: we build secure file transfer software for Windows. Sysax Multi Server is an FTP, FTPS, SFTP, and HTTPS server. Sysax FTP Automation handles scheduled, scripted transfers. Free trials are on the download page.