Last active
January 28, 2026 00:59
-
-
Save Krzysiu/b71c461e5aacddc54e425da5aa986f74 to your computer and use it in GitHub Desktop.
Important exiftool commands - both basic and advanced
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # ============== | |
| # TECHNICAL NOTE | |
| # ============== | |
| # When there's a part which you should change to your enviroment (like directory), it's marked as eg. {$PATH}. | |
| # In conditions or print output format, where tags are marked with $ on the beggining, like $DateTimeOriginal, I'm just | |
| # leaving example tag name, so it won't confuse y'all with "${$FOO}" | |
| # | |
| # For Windows give a try alternative ExifTool build: https://oliverbetz.de/pages/Artikel/ExifTool-for-Windows | |
| # If there's something you miss, feel free to ask in comments. Or google (or duckduckgo, whatever) for it. | |
| # Or ask on the official forums - https://exiftool.org/forum/index.php - that's one of the most friendly places ever | |
| # and answers are usually very fast, often from creator himself or some other professional. | |
| # If command differ for Windows and Linux, it's marked as WIN or LIN | |
| # Every command ends with ".". It's where it should look for files. If it's current directory, use ".", | |
| # if path is different, use e.g. "c:\photo\." | |
| # If there's percent sign (%) in command line, it will work in Linux and Windows command line. For Windows | |
| # batch file, change it to double percent (%%) | |
| # Get photos made in the same month/day, but different year (a.k.a. Facebook Memories) | |
| exiftool -r -d "%m-%d" -if '$DateTimeOriginal =~ /'"$(date +%m-%d)"' /' -filename . # LIN | |
| exiftool -r -d "%m-%d" -if "$DateTimeOriginal =~ /{$MONTH-$DAY}/" -filename . # WIN - fill month/day by yourself :P | |
| # or use this ugly, but working batch script | |
| #for /f "tokens=2 delims==" %%i in ('wmic os get localdatetime /value') do set "dt=%%i" | |
| #set "month=%dt:~4,2%" | |
| #set "day=%dt:~6,2%" | |
| #set "pattern=%month%-%day%" | |
| #exiftool -r -if "$DateTimeOriginal =~ /%pattern%/" -p "${FilePath;s/\//\\/g}" d:\_foto\. | |
| # LIN: process only certain extensions. Looks simple, but in Linux *.cr2 would ommit IMG_1337.CR2 (i.e. upper case) | |
| exiftool {$COMMANDS} -ext cr2 . | |
| # Output full, absolute path with filename | |
| exiftool {$COMMANDS} -p "${FilePath;s/\//\\/g}" . # WIN (changes / to \) | |
| exiftool {$COMMANDS} -p "${FilePath}" . # LIN | |
| # Get full (including namespace!) attribute name (useful for setting/getting them, but also for conditions [!] - ctrl+f GETTAG) | |
| # Example output: | |
| # -XMP:Rating=0 | |
| # -MakerNotes:MacroMode=Normal | |
| # Now we know that to change rating, we should use -XMP:Rating | |
| exiftool -args -G0 . | |
| # Offset date. | |
| # ${PATTERN} is e.g. "12:0:6 1:3:0"- it means to change year to 12 years later, keep month, 6 days later, | |
| # 1 hour later, 3 minutes later, keep seconds. OFC it's yy:mm:dd hh:mm:ss | |
| # ${OFFSET} is + or - | |
| # Alldates is for all dates (duh!) but you may want to use just some of them, like FileModifyDate or DateTimeOriginal | |
| # So the command to change exif date of all hours by +2 would be: | |
| # exiftool "-DateTimeOriginal+=0:0:0 2:0:0" | |
| exiftool "-Alldates{$OFFSET}={$PATTERN}" . | |
| # Write multiline description | |
| exiftool -ec -description="foo\nbar" . | |
| # Compute hash of image DATA (meaning that files with different metadata will yield the same hash) | |
| # That's wonderful for finding duplicates, which most duplicate finders won't see (as file hash differs) | |
| # The following command will output something like: | |
| # somepath/IMG_1285.CR2|cad6c851659a4d5828da10655c7987c9 | |
| # somepath/IMG_1285_NO_METADATA.CR2|cad6c851659a4d5828da10655c7987c9 | |
| # which then might be fed to script checking for duplicate values | |
| exiftool -p "$filepath|$imagedatamd5" . | |
| # Extract big raw preview (usually embedded JPEG) to file, where filename matches original and extension is set | |
| # to the proper format of preview. E.g. IMG_1337.CR2 will be extracted to IMG_1337.jpg | |
| exiftool -b -PreviewImage -W "%f.%s" -ext cr2 . | |
| # Changing date format is useful not just for display, but also for processing and conditions. | |
| # Here: move files to YYYY-MM directories | |
| exiftool -d "%%Y-%%m" "-directory<DateTimeOriginal" . | |
| # Rotate JPEG preview in raw. Because changing orientation in metadata won't fix preview that | |
| # most viewers will show. | |
| # Requires JPEGTRAN (official download: https://jpegclub.org/jpegtran/) | |
| # WARNING: Use with caution. For some reason some thumbnailers don't like rotated jpegs | |
| # -overwrite_original is DISCOURAGED | |
| # {$ROTATE} is: | |
| # 90 - Clockwise | |
| # 270 - Counterclockwise | |
| # 180 - Flip | |
| # So e.g. to rotate CW, use jpegtran -rotate {$ROTATE} -copy all -outfile {$PATHTEMP} {$PATHIN} | |
| # {$PATHIN} is just name of your input file | |
| # {$PATHTEMP-ORIG} and {$PATHTEMP-ROTATED} are two different paths to temporary files. | |
| # For Windows you may use %TEMP%\preview.jpg and %TEMP%\preview-rotated.jpg | |
| # For Bash (e.g. Linux) use "tmp_file=$(mktemp --suffix=.jpg)" and then change {$PATHTEMP-ORIG} to $tmp_file | |
| # (two times, two vars, for two different files) | |
| exiftool -PreviewImage -b {$PATHIN} > {$PATHTEMP-ORIG} | |
| jpegtran -rotate {$ROTATE} -copy all -outfile {$PATHTEMP-ROTATED} {$PATHTEMP-ORIG} | |
| exiftool "-PreviewImage<={$PATHTEMP-ROTATED}" {$PATHIN} | |
| del {$PATHTEMP} # WIN | |
| rm {$PATHTEMP} # LIN | |
| # ========== | |
| # CONDITIONS | |
| # ========== | |
| # Use as part of the command, e.g. | |
| # exiftool -if "lc($Software) =~ /inkscape/" -title="Inkscape file!" . | |
| # Condition: image size (in pixels). OFC you can change < to > | |
| -if "$imagesize and ($imagewidth<{$WIDTH} or $imageheight<{$HEIGHT})" | |
| # Case insensitive condition - look for {$string} (must be lowercase)! | |
| # So, "lc($Software) =~ /inkscape/" fits Inkscape, inkscape, iNkScApE etc. | |
| # As =~ looks for string inside string, it will fit "Inkscape 5" or "This is Inkscape" | |
| -if "lc($Software) =~ /{$string}/" | |
| # Boolean conditions | |
| -if "($SignificantBits eq '8 8 8 8') || (lc($Software) =~ /inkscape/)" # OR | |
| -if "($SignificantBits eq '8 8 8 8') && (lc($Software) =~ /inkscape/)" # AND | |
| # Check if a specific tag contains given string (ctrl+f GETTAG) | |
| -if "$EXIF:Model =~ /(Samsung)/" | |
| # Check tag count (warning: I noticed some tags have ";" or "|" separator, here it's for ",") | |
| # {$COUNT} is number you want to check against | |
| # {$OPERATOR} is comparison operator | |
| # For e.g. to check if there's single tag in $RegionPersonDisplayName (ctrl+f GETTAG): | |
| # -if 'scalar(split(/,/, $RegionPersonDisplayName)) == 1' | |
| -if "scalar(split(/,/, $RegionPersonDisplayName)) {$OPERATOR} {$COUNT}" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment