Skip to main content

Documentation Index

Fetch the complete documentation index at: https://photocli.com/llms.txt

Use this file to discover all available pages before exploring further.

photo-cli copy reads photos from an input folder, renames and reorganizes them into a new output folder using each photo’s EXIF date taken and optional GPS reverse geocode address, then writes a CSV report summarizing every file processed. Your source folder is never touched.

Synopsis

photo-cli copy [options]

Key behavior

  • Reads all photos from the input folder (or the current directory if --input is omitted).
  • Copies each photo to the output folder with a new name and folder structure derived from EXIF metadata.
  • Photos with missing dates or coordinates are handled according to the --no-taken-date and --no-coordinate flags rather than silently dropped.
  • Generates photo-cli-report.csv in the output folder root after every run.
  • Never modifies, moves, or deletes files in the input folder.
Add --dry-run (-d) to simulate the entire process without writing any files to disk. A separate photo-cli-dry-run.csv report is produced so you can review what would happen before committing.

Required arguments

--output, -o
string
required
File system path where the new organized folder will be created. The folder is created automatically if it does not already exist.
--naming-style, -s
enum
required
File naming strategy applied to every copied photo. Choose one of the following values:
NameValue
Numeric1
Day2
DateTimeWithMinutes3
DateTimeWithSeconds4
Address5
DayAddress6
DateTimeWithMinutesAddress7
DateTimeWithSecondsAddress8
AddressDay9
AddressDateTimeWithMinutes10
AddressDateTimeWithSeconds11
--process-type, -f
enum
required
Controls how photos are read from the input folder and how the output folder hierarchy is structured.
NameValue
Single1
SubFoldersPreserveFolderHierarchy2
FlattenAllSubFolders3
--number-style, -n
enum
required
Number formatting used when --naming-style is Numeric or when disambiguating photos that share the same generated name.
NameValue
AllNamesAreSameLength1
PaddingZeroCharacter2
OnlySequentialNumbers3
--no-taken-date, -t
enum
required
Action to take when a photo has no EXIF date taken.
NameValue
Continue0
PreventProcess1
DontCopyToOutput2
InSubFolder3
AppendToEndOrderByFileName4
InsertToBeginningOrderByFileName5
--no-coordinate, -c
enum
required
Action to take when a photo has no GPS coordinate.
NameValue
Continue0
PreventProcess1
DontCopyToOutput2
InSubFolder3

Optional arguments

--input, -i
string
File system path to read photos from. Defaults to the current working directory. No files in this path are ever modified.
--dry-run, -d
boolean
Simulate the copy process without writing any files to the output folder. No extra value required — pass the flag alone.
--group-by, -g
enum
Groups photos into date- or address-based subfolders. Cannot be used when --process-type is SubFoldersPreserveFolderHierarchy.
NameValue
YearMonthDay1
YearMonth2
Year3
Address4
AddressFlat5
AddressHierarchy6
--folder-append, -a
enum
Appends date range or address information to folder names cloned from the source hierarchy. Must be combined with --folder-append-location. Only applies when --process-type is SubFoldersPreserveFolderHierarchy.
NameValue
FirstYearMonthDay1
FirstYearMonth2
FirstYear3
DayRange4
MatchingMinimumAddress5
--folder-append-location, -p
enum
Controls whether the appended string is placed before or after the original folder name. Must be combined with --folder-append.
NameValue
Prefix1
Suffix2
--invalid-format, -x
enum
Action to take when a file cannot be parsed as a valid photo format.
NameValue
Continue (default)0
PreventProcess1
DontCopyToOutput2
InSubFolder3
--verify, -v
boolean
Verifies every copied file by comparing its SHA1 hash against the original. All hashes are also written to sha1.lst in the output folder so you can re-verify later with sha1sum --check sha1.lst.
--expected-day-range, -w
integer
Maximum expected day difference between the earliest and latest photo taken dates. If the range exceeds this value, the process stops before copying.
--missing-reverse-geocode, -z
enum
Action to take when any photo has missing reverse geocode information.
NameValue
Continue (default)0
PreventProcess1
--reverse-geocode, -e
enum
Third-party provider used to resolve GPS coordinates into a human-readable address. See reverse geocoding overview for provider setup and API key details.
NameValue
Disabled0
BigDataCloud1
OpenStreetMapFoundation2
GoogleMaps3
LocationIq5
--openstreetmap-properties, -r
string
Space-separated OpenStreetMap address property names used to build the address string. Required when --reverse-geocode is OpenStreetMapFoundation or LocationIq. Example: country city town suburb. Use photo-cli address to discover available property names for a given photo.
--bigdatacloud-levels, -u
string
Space-separated BigDataCloud admin level numbers used to build the address string. Required when --reverse-geocode is BigDataCloud.
--bigdatacloud-key, -b
string
API key for BigDataCloud. You can also set this via the PHOTO_CLI_BIG_DATA_CLOUD_API_KEY environment variable or the BigDataCloudApiKey setting.
--googlemaps-types, -m
string
Space-separated Google Maps address component types. Required when --reverse-geocode is GoogleMaps.
--googlemaps-key, -k
string
API key for Google Maps. You can also set this via the PHOTO_CLI_GOOGLE_MAPS_API_KEY environment variable or the GoogleMapsApiKey setting.
--locationiq-key, -q
string
API key for LocationIq. You can also set this via the PHOTO_CLI_LOCATIONIQ_API_KEY environment variable or the LocationIqApiKey setting.
--has-paid-license, -h
boolean
Bypass the free-tier rate limit when using LocationIq with a paid license.
--language, -l
string
Language/culture value to get localized address results from the reverse geocode provider. See your provider’s documentation for supported values.

Example

The following command preserves your existing folder hierarchy, renames each file with its date and address, prefixes each folder with the date range of photos inside it, and routes photos with missing data into dedicated subfolders.
photo-cli copy \
  --process-type SubFoldersPreserveFolderHierarchy \
  --naming-style DateTimeWithSecondsAddress \
  --number-style PaddingZeroCharacter \
  --folder-append DayRange \
  --folder-append-location Prefix \
  --reverse-geocode OpenStreetMapFoundation \
  --openstreetmap-properties country city town suburb \
  --output photo-cli-test \
  --no-coordinate InSubFolder \
  --no-taken-date InSubFolder \
  --verify

Console output

Searching photos: finished. 17 photos found.
Parsing photo exif information: finished.
This OpenStreetMapFoundation provider is using rate limit of 1 seconds between each request
Reverse Geocoding: finished.
Directory grouping: finished.
Processing target folder: finished.
Verified all photo files copied successfully by comparing file hashes from original photo files.
All files SHA1 hashes written into file: sha1.lst. You may verify yourself with `sha1sum --check sha1.lst` tool in Linux/macOS.
Writing csv report: finished.
- 17 photos copied.
- 4 directories created.
- 15 photos has taken date and coordinate.
- 1 photos has taken date but no coordinate.
- 1 photos has no taken date and coordinate.

Folder structure before and after

OriginalAfter photo-cli
├── DSC_5727.jpg├── 2005.08.13_09.47.23-Kenya.jpg
├── GOPR6742.jpg├── 2012.06.22_19.52.31-United Kingdom-Ascot-Sunninghill and Ascot.jpg
├── Italy album/├── 2005.12.14-2008.10.22-Italy album/
│ ├── DJI_01732.jpg│ ├── 2008.10.22_16.29.49-Italia-Arezzo.jpg
│ └── IMG_2371.jpg├── Italy album/no-address/IMG_2371.jpg
└── Spain Journey/├── 2015.04.10-2015.04.10-Spain Journey/
└── IMG_5397.jpg└── Spain Journey/no-address-and-no-photo-taken-date/IMG_5397.jpg

CSV report

After every run, photo-cli-report.csv is created in the output folder root. It contains one row per photo with the following columns:
ColumnDescription
PhotoPathAbsolute path to the original source file
PhotoNewPathRelative path to the copied file in the output folder
PhotoDateTakenEXIF date and time the photo was taken
ReverseGeocodeFormattedHuman-readable address built from the configured provider and properties
LatitudeGPS latitude extracted from EXIF
LongitudeGPS longitude extracted from EXIF
PhotoTakenYearYear component of the taken date
PhotoTakenMonthMonth component of the taken date
PhotoTakenDayDay component of the taken date
PhotoTakenHourHour component of the taken date
PhotoTakenMinuteMinute component of the taken date
PhotoTakenSecondsSeconds component of the taken date
Address1Address8Individual address components returned by the reverse geocode provider
You can open this file in any spreadsheet application (Excel, Google Sheets, LibreOffice Calc, Apple Numbers) or import it into Google My Maps or Google Earth for location exploration.