cs2cs converts coordinates between reference systems, and two mistakes wreck most transformations: reversed axis order and a missing datum grid. This gives you a repeatable way to run the conversion and check the result before you trust it. The examples use cs2cs from PROJ 9.4.0, supplied here by Debian package proj-bin version 9.4.0-1build2.
Allow about fifteen minutes. You need a shell and proj-bin. The commands read standard input or ordinary files and write transformed text; none of the examples needs sudo. Coordinate transformations can affect published maps and measurements, so keep the original input and verify a known point before replacing anything.
Confirm the binary and version before copying an example into a script. This is a read-only check:
$ command -v cs2cs
/usr/bin/cs2cs
$ dpkg-query -W -f='${Package} ${Version}\n' proj-bin
proj-bin 9.4.0-1build2
$ cs2cs --version
Rel. 9.4.0, March 1st, 2024
<cs2cs>:
The final diagnostic is normal for this release: cs2cs prints its release line and then treats the unsupported --version as an option. Use the release line as the version check. The installed manual is the contract for this machine, and it describes the same release as PROJ 9.4.
Start with an EPSG example whose output is easy to compare. This converts WGS 84 geographic coordinates to WGS 84 / UTM zone 31N:
$ printf '%s\n' '45N 2E' | cs2cs EPSG:4326 EPSG:32631
421184.70 4983436.77 0.00
With an authority CRS such as EPSG:4326, PROJ enforces the CRS axis order. The first input value is latitude and the second is longitude, so 45N 2E means latitude 45 degrees north and longitude 2 degrees east. This is easy to misread because many GIS interfaces display longitude first. Do not silently swap values to match a different application; establish that application's declared order first.
Checkpoint: rerun the command with an explicit decimal output format if another program needs numbers rather than the default projected formatting:
$ printf '%s\n' '45N 2E' | cs2cs -f '%.3f' EPSG:4326 EPSG:32631
421184.697 4983436.768 0.000
The first two values are the transformed coordinate. The trailing 0.000 is the third coordinate that cs2cs emits for this operation. Preserve it when your downstream format expects a third value, or parse the output according to the schema you control.
cs2cs reads the first two whitespace-separated fields on each input line. With no filename, it reads standard input. A hyphen explicitly names standard input, while filenames are processed from left to right. Text after the coordinate fields is normally copied to the output line, which is useful for an identifier:
$ printf '%s\n' '45N 2E paris-centre' | cs2cs EPSG:4326 EPSG:32631
421184.70 4983436.77 0.00 paris-centre
Use a temporary output when converting a file. Shell redirection with > truncates its destination before cs2cs runs, so never point it at the only copy of valuable source data:
$ cs2cs EPSG:4326 EPSG:32631 coordinates.txt > coordinates.utm.tmp
$ test -s coordinates.utm.tmp && echo 'output is non-empty'
output is non-empty
$ mv coordinates.utm.tmp coordinates.utm.txt
The final mv is the state-changing step. If the command fails or the verification is not convincing, remove the temporary file and keep the original. Do not run mv until you have checked the output range and a known test coordinate.
EPSG codes are usually the clearest choice because they identify a database CRS and allow PROJ to select an operation. You can also provide PROJ strings, with the source definition before +to and the destination definition after it:
$ printf '%s\n' '45N 2E' | cs2cs \
+proj=latlong +datum=WGS84 \
+to +proj=utm +zone=31 +datum=WGS84
421184.70 4983436.77 0.00
Use the form that your data contract specifies. A PROJ string can be concise, but it does not by itself explain every modern datum or grid choice. For repeatable work, record the source CRS, target CRS, PROJ version, input axis order and whether network access was enabled alongside the transformed file.
The -r option reverses the first two expected input values, and -s reverses the first two expected output values. They are escape hatches for a known axis-order mismatch, not general fixes. Test one labelled point before applying either option to a batch.
Some transformations need resource files such as datum-shift grids. If a suitable grid is unavailable, PROJ may select an approximation unless you require the best known operation. For a strict run, add --only-best:
$ printf '%s\n' '-111.5 45.25919444444' | cs2cs --only-best \
+proj=latlong +datum=NAD83 \
+to +proj=utm +zone=10 +datum=NAD27
* * inf
The exact diagnostic names the missing grid and the failed operation. That is a useful failure: it prevents a batch from quietly using a lower-quality approximation. Install or provide the required grid through your normal PROJ data management process, then rerun and compare the result. Do not treat an inf output as a usable coordinate.
PROJ 9.4 can also attempt remote grids when PROJ_NETWORK=ON is set. That is a network and reproducibility decision, not a harmless formatting switch. If you use it, record the setting and make sure the machine is allowed to contact the configured CDN. For an offline or audited job, leave it unset and fail clearly when required resources are absent.
Use -v to print the cartographic control parameters tested and used before the input data. This can reveal that the selected operation is not the one you expected:
$ printf '%s\n' '45N 2E' | cs2cs -v EPSG:4326 EPSG:32631
# diagnostic lines are printed before the transformed coordinate
421184.70 4983436.77 0.00
If the output is wrong, first check the CRS codes, axis order, units and the order of the two CRS arguments. Then test a point whose correct result you already know. A successful exit status means the process completed; it does not prove that the CRS choice was correct.
Use -e to choose a visible error marker for a text pipeline. The default marker is * separated by tabs, so a parser should reject non-numeric fields rather than accepting a partial line. Keep the original input and capture standard error when diagnosing a failed batch.
cs2cs release and package.* and inf as errors, not coordinates.