Как удалить файлы JPG, но только если существует соответствующий файл RAW?

Все мои ранние (Canon G2) фотографии были в формате JPG, но когда я получил свой Nikon D90, я сначала снимал в формате JPG, затем переключился на RAW+JPG, а теперь хочу переключиться только на RAW.

У меня буквально тысячи фотографий на жестком диске. Фотографии находятся в подкаталогах (по дате) в одном каталоге под названием «Импорт».

Я собираюсь импортировать все эти фотографии в Lightroom 3.0, однако я хотел бы удалить все файлы JPG, но только там, где уже есть соответствующий файл RAW (т.е. я больше не хочу хранить версии JPG и RAW одного и того же файл).

Если бы я мог легко сделать это в Lightroom (после импорта всего, включая дубликаты файлов JPG), это было бы здорово. Также было бы хорошо, если бы был простой способ сделать это перед импортом файлов (но, надеюсь, это не потребовало бы посещения каждого каталога в поисках имен файлов с расширениями JPG и NEF).

Кто-нибудь знает, как это сделать (в Lightroom или с помощью какого-либо инструмента/скрипта в Windows)?

Все ли ваши файлы jpg и файлы RAW имеют как минимум одинаковую строку (к ним можно добавить другие символы)? Например, IMG_1234_portrait_picture.jpg и IMG_1234.CR2.
Я думаю, что все мои пары JPG/NEF имеют одинаковое имя файла (за исключением расширения).
Я проголосую за то, чтобы переместить это в Stack Overflow, где вы должны получить ответ в течение нескольких минут =)
@anon: Как именно это относится к StackOverflow? Это, безусловно, вопрос по теме, поскольку он касается инструментов управления изображениями и редактирования фотографий. Помимо косвенной ссылки на сценарий... это не имеет ничего общего с программированием.
@jrista - Спрашивающий сказал, что можно обрабатывать файлы / папки перед импортом в Lightroom. Для меня решение на основе сценариев было бы идеальным, потому что оно было бы независимым от инструментов, более быстрым, более переносимым и настраиваемым. В абстрактном смысле это даже не зависит от фактического типа файлов, с которыми мы имеем дело. Но опять же, я программист =)
@anon Это определенно не вопрос программирования , поэтому, хотя он может подойти для суперпользователя, я также считаю его здесь актуальным, учитывая его сильное и конкретное приложение для управления фотографиями.
@Rowland - достаточно честно =)
Я думаю, что это входит в широкий спектр того, что мы договорились по теме, но я также думаю, что это не совсем конкретно для фотографий, и, возможно, на сайте SE с более широким охватом можно было бы получить больше и быстрее ответов. Но теперь у нас есть некоторые ответы, так что, думаю, все в порядке. :)
Когда я набирал вопрос, я понял, что проблемный домен на самом деле не был фотографическим, и что самым простым ответом почти наверняка было бы использование скрипта (и ответ анона отлично работает, спасибо!), но я все равно добавил вопрос, потому что Я надеялся узнать что-то новое о Lightroom.
Я голосую за то, чтобы закрыть этот вопрос как не по теме, потому что речь идет не о фотографии, а об управлении файлами, которые просто оказались фотографиями. Вопрос и ответ были бы такими же, если бы рассматриваемые два типа файлов были любыми другими типами файлов, которые можно было бы перевести из одной формы в другую, например файлы .doc и .pdf и т. д.

Ответы (11)

В Windows перейдите в папку и запустите в командной строке:

for /f "delims==" %r in ('dir /b *.nef') do del "%~dpr%~nr.jpg" 2> nul

По сути, он проходит через текущую папку, просматривает файлы NEF и удаляет JPG, если он есть. Он игнорирует любые ошибки, если JPG отсутствует.

Если вам нужны подпапки, включите /sв dirкоманду.

Отлично, спасибо! Конечно, прежде чем я запустил его в первый раз, я изменил «del» на «echo». Затем я запустил «помощь для», чтобы понять, что он делает. Очевидно, прошло много времени с тех пор, как я смотрел на сценарии командной строки, потому что я понятия не имел, что у команды «for» так много опций.
Без проблем! Во время тестирования я также использовал «эхо» =) Чтобы увидеть больше вывода, удалите «2> nul». Я собирался сделать что-то подобное для своих собственных файлов NEF/JPG, и это была прекрасная возможность.
Фантастика. Очистка и старая структура папок raw + jpeg стала проще с помощью одной аккуратной команды :)

Вот модифицированная версия Python-скрипта Tomy . Отличия:

  • разрешено несколько необработанных расширений
  • удалять jpg только в том случае, если пары находятся в одной папке (избегайте случайного удаления jpg, названного как необработанный файл в другой папке)
  • без учета регистра

#!/usr/bin/env python
# Script:      remove_jpg_if_raw_exists.py
#
# Description: This script looks in all sub directories for
#              pairs of JPG and RAW files.
#              For each pair found the JPG is moved to a
#              waste basket directory.
#              Otherwise JPG is kept.
#
# Author:      Thomas Dahlmann
# Modified by: Renaud Boitouzet

import os
import shutil

# define your file extensions here, case is ignored.
# Please start with a dot.
# multiple raw extensions allowed, single jpg extension only
raw_extensions = (".Dng", ".cR2", ".nef", ".crw")
jpg_extension = ".jPg"

# define waste basket directory here. Include trainling slash or backslash.
# Windows : waste_dir = "C:\path\to\waste\"
waste_dir = "/Users/marvin/Pictures/waste/"

##### do not modify below ##########

# find files
def locate(folder, extensions):
    '''Locate files in directory with given extensions'''
    for filename in os.listdir(folder):
        if filename.endswith(extensions):
            yield os.path.join(folder, filename)

# make waste basket dir
if not os.path.exists(waste_dir):
    os.makedirs(waste_dir)

# Make search case insensitive
raw_ext = tuple(map(str.lower,raw_extensions)) + tuple(map(str.upper,raw_extensions))
jpg_ext = (jpg_extension.lower(), jpg_extension.upper())

root=os.curdir
#find subdirectories
for path, dirs, files in os.walk(os.path.abspath(root)):
    print path
    raw_hash = {}
    for raw in locate(path, raw_ext):
        base_name = os.path.basename(raw)
        base_name = os.path.splitext(base_name)[0]
        raw_hash[base_name] = True

    # find pairs and move jpgs of pairs to waste basket
    for jpg in locate(path, jpg_ext):
        base_name = os.path.basename(jpg)
        base_name = os.path.splitext(base_name)[0]
        if base_name in raw_hash:
            jpg_base_name_with_ext = base_name + jpg_extension
            new_jpg = waste_dir + jpg_base_name_with_ext
            print "%s: %s = %s => %s" % (path, base_name, jpg, waste_dir)
            if os.path.exists(new_jpg):
                os.remove(jpg)
            else:
                shutil.move(jpg, new_jpg)
отличный сценарий. Я буду использовать его, потому что у него много хороших аварийных переключений. Однако вы должны добавить эту строку #!/usr/bin/env pythonв начало. В противном случае у меня были странные ошибки ImageMagick (кажется, мой Mac открывает файлы .py с помощью ImageMagick)
Просто к вашему сведению: кажется, что это не работает, когда файлы действительно названы .jPg. Это также не работает, когда файлы находятся на внешнем диске и в ненужном каталоге, например, в каталоге /home.
некоторые исправления: gist.github.com/therealmarv/ec603bd4a91d51092a18
@therealmarv: на самом деле с ImageMagick происходит то, что скрипт открывается в оболочке, а не в ImageMagick, но «импорт» - это название инструмента ImageMagick.

Вот скрипт Python , который перемещает JPGфайлы, когда соответствующий RAWфайл не существует. Полезно в Mac OS X !

import os
import shutil

raw_ext = '.CR2'
jpg_ext = '.JPG'
destination = '/Users/JohnSmith/Desktop/jpgs/'

for filename in os.listdir('.'):
    (shortname, extension) = os.path.splitext(filename)

    if extension == raw_ext:
        if os.path.isfile(shortname + jpg_ext):
            print 'Moving ' + shortname + jpg_ext + '...'
            shutil.move(shortname + jpg_ext, destination)
  • Создать пустую библиотеку
  • В главном меню Lightroom выберите «Правка» > «Настройки» (Windows) или «Lightroom» > «Настройки» (Mac OS).
  • В общих настройках снимите флажок «Обрабатывать файлы JPEG рядом с файлами Raw как отдельные фотографии».
    • Это должно быть по умолчанию.
  • Импортируйте все свои файлы (вы можете выбрать подпапки поиска), сказав, что нужно переместиться в новое место.
  • Файлы JPG, содержащие файлы RAW, останутся в исходном месте, чтобы вы могли их удалить.

Насколько я понимаю, на миниатюре в лайтруме может быть написано RAW+JPG, но на самом деле JPG не хранится и не доступен каким-либо образом.

Вы также можете написать довольно простой пакетный скрипт на любом языке программирования.

Мне нравится сценарий bash для OS X (от T.Toivonen ), но я заметил несколько проблем.

  • Ему не нравились мои имена каталогов, содержащие пробелы. Это потребовало немного другой обработки команды find.

  • Оригинальный скрипт работает только для расширений нижнего регистра. Я немного улучшил эту часть скрипта, чтобы учесть расширения, которые также пишутся в верхнем регистре. Обратите внимание, что он принимает только пары DNG+JPGили dng+jpgи игнорирует любые комбинации, такие как DNG+jpgили DnG+JpG.

  • Первоначальное решение предлагало только одно wastedirместоположение, тогда как мое исправление позволяет создавать подкаталог в каждой ветке каталога по мере его перемещения. Вы определяете имя каталога перед циклом.

  • Мне нравится видеть, что происходит, особенно когда используются команды mvили rm;)

Для экономии места я показываю только последнюю часть скрипта, начиная с установки a basedirи wastedirцикла.

[...]

#Now set it as a basedir
BASEDIR=$arg
WASTEDIR=duplicates
find "$BASEDIR" -iname '*.dng' -print0 | while read -d $'\0' filename 
    do
    filepath="${filename%/*}"
    basename="${filename##*/}"
    prefix="${basename%%.*}"
    suffix=${filename##*.}
    if [[ "$suffix" =~ [A-Z] ]]; then rsuffix="JPG"; else rsuffix="jpg"; fi 
    if [ -e "$filepath/$prefix.$rsuffix" ]; then
        let counter="$counter+1"
        if (( $isSetE==1 )); then
            echo "FOUND: $filepath/$prefix.$rsuffix"
        fi
        if (( $isSetM==1 )); then
            echo "Moving $filepath/$prefix.$rsuffix to $filepath/$WASTEDIR"
            if [ ! -d "$filepath/$WASTEDIR" ]; then mkdir "$filepath/$WASTEDIR"; fi
            mv "$filepath/$prefix.$rsuffix" "$filepath/$WASTEDIR"
        fi
        if (( $isSetD==1 )); then
            echo "Removing duplicate $filepath/$prefix.$rsuffix"
            rm "$filepath/$prefix.$rsuffix"
        fi
    fi
done
Вопрос был помечен как «windows», поэтому вы могли бы сказать, как это можно заставить работать в типичной системе Windows. Например, я запускаю Cygwin (и я планирую лучше взглянуть на этот ответ, когда буду на рабочем столе, чтобы немного изменить поведение)

Вот решение для bash(Linux или Mac OS X). В Windows вы можете установить Cygwin , чтобы получить копию bash.

keep=$(ls | grep -v ps | grep -A1 JPG | grep NEF)
for i in $keep ; do
   mv $i $i.keep
done

ls | egrep -v '(JPG|keep)' | xargs rm -f

change=$(ls | grep keep | sed 's/.keep//g')
for i in $change ; do
   mv $i.keep $i
done

Вот еще одна bashверсия с использованием find(Linux). Как и в случае с ответом Бена Пингилли , вы можете установить Cygwin , чтобы получить bash в Windows.

#!/bin/bash
read -p "please enter file suffix for raw format (e.g ORF, NEF, CR2): " suffix

find . -type f -iname "*.${suffix}" | \
while read line
do
  lowercase=$(echo "$line" | sed "s/${suffix}/jpg/gi")
  uppercase=$(echo "$line" | sed "s/${suffix}/JPG/gi")

  if [ -f "${lowercase}" ]
  then
    rm -v "${lowercase}"
  elif [ -f "${uppercase}" ]
  then
    rm -v "${uppercase}"
  else
    echo "${line}: no jpg present"
  fi
done

Вот мой взгляд на этот вопрос. Много хороших идей пришло из более ранних сценариев, упомянутых здесь.

Это bash-скрипт для OS X. Он ищет файлы, которые существуют с тем же базовым именем файла и dng+jpgрасширениями. Если jpgнайден файл с точно таким же именем, как dngи , то это имя файла отображается ( -e), файл перемещается ( -m) или удаляется ( -d).

Он будет проходить через подпапки, поэтому вы можете использовать его для всего каталога или только его частей.

Для других необработанных расширений файлов просто замените *.dngв скрипте предпочитаемое расширение.

Предупреждение: у вас может быть два разных изображения с одинаковым именем, но с разным расширением. Это неизбежные жертвы этого сценария.

Вот как использовать скрипт:

Usage: dng-jpg.sh [-m <path>] [-d <path>] [-e <path>] [-h]

-m: for move   (moves files to <path>/duplicates)
-d: for delete (deletes duplicate files)
-e: for echo   (lists duplicate files)
-h: for help 

Основное использование будет работать следующим образом:

$ ./dng-jpg.sh -e /Volumes/photo/DNG/2015

Это будет отображать все имена jpgфайлов, которые соответствуют критериям наличия обоих файлов dngи jpgфайлов с одинаковым именем.

Результат будет выглядеть примерно так:

Echo selected with path: /Volumes/photo/DNG/2015
/Volumes/photo/DNG/2015/03/18/2015-03-18_02-11-17.jpg
/Volumes/photo/DNG/2015/06/01/2015-06-01_05-10-50.jpg
/Volumes/photo/DNG/2015/06/01/2015-06-01_05-10-56.jpg
/Volumes/photo/DNG/2015/06/01/2015-06-01_05-11-39.jpg
/Volumes/photo/DNG/2015/06/01/2015-06-01_05-11-54.jpg
/Volumes/photo/DNG/2015/06/01/2015-06-01_05-12-26.jpg
/Volumes/photo/DNG/2015/06/01/2015-06-01_05-12-43.jpg
/Volumes/photo/DNG/2015/06/01/2015-06-01_05-13-21.jpg
/Volumes/photo/DNG/2015/06/01/2015-06-01_05-13-56.jpg
9 files found.

Теперь, если я хочу удалить файлы, я бы просто переключил -eна -d:

$ ./dng-jpg.sh -d /Volumes/photo/DNG/2015

Или, если я хочу переместить файлы в /duplicates, я бы выполнил это с расширением -m.

$ ./dng-jpg.sh -m /Volumes/photo/DNG/2015

Теперь дубликаты jpgфайлов будут в/Volumes/photo/DNG/2015/duplicates

Вот скрипт: dng-jpg.sh

#!/bin/bash

# Init variables
isSetM=0
isSetD=0
isSetE=0
isSetCount=0
counter=0

#Display usage info
usage() {

    cat <<EOF

Usage: dng-jpg.sh [-m <path>] [-d <path>] [-e <path>] [-h]

-m: for move   (moves files to <path>/duplicates)
-d: for delete (deletes duplicate files)
-e: for echo   (lists duplicate files)
-h: for help 

EOF
  exit 1
}

#Check for parameters
while getopts ":m:d:e:h" opt; do
  case ${opt} in
    m)
        isSetM=1
        let isSetCount="$isSetCount+1"
        arg=${OPTARG}
      echo "Move selected with path:" $arg
      ;;
    d)
        isSetD=1
        let isSetCount="$isSetCount+1"
        arg=${OPTARG}
      echo "Delete selected with path:" $arg
      ;;
    e)
        isSetE=1
        let isSetCount="$isSetCount+1"
        arg=${OPTARG}
      echo "Echo selected with path:" $arg
      ;;
    h)
        let isSetCount="$isSetCount+1"
        usage
      ;;
    \?)
      echo "Invalid option: -$OPTARG" >&2
      usage
      ;;
    :)
      echo "Option -$OPTARG requires a directory argument." >&2
      usage
      ;;
    *)
      usage
      ;;
  esac
done

# If no parameters, show usage help and exit
if test -z "$1"; then
    usage
fi

# If multiple parameters (not counting -a), show usage help and exit
if (($isSetCount > 1)); then
    usage
fi

#Verify directory
if [ ! -d "$arg" ]; then
  echo "$arg is not a path to a directory." >&2
  usage
fi

#Now set it as a basedir
BASEDIR=$arg
WASTEDIR="$BASEDIR/duplicates/"
if (( $isSetM==1 )); then
    mkdir $WASTEDIR
fi

for filename in $(find $BASEDIR -name '*.dng' -exec echo {} \; | sort); do
   prefix=${filename%.dng}
    if [ -e "$prefix.jpg" ]; then
        let counter="$counter+1"
        if (( $isSetE==1 )); then
            echo "$prefix.jpg"
        fi
        if (( $isSetM==1 )); then
            mv $prefix.jpg $WASTEDIR
        fi
        if (( $isSetD==1 )); then
            rm $prefix.jpg
        fi
    fi
done

echo "$counter files found."

Вот bashскрипт для Mac OS X. Он может работать в Linux с некоторыми изменениями.

#!/bin/bash
read -p "Delete JPEGs when DNG exists? Ctrl-C to cancel. [Enter] to continue: "

for FILE in *.dng; do
  JPG_FILE=$(echo "$FILE" | sed "s/dng/jpg/g")
  rmtrash "${JPG_FILE}" 1>/dev/null
done

rmtrashэто утилита, которая перемещает файлы в корзину, а не удаляет их сразу. Вы можете получить его от MacPorts таким образом:

sudo port install rmtrash

Если вы хотите избежать этого, просто замените rmtrashв скрипте на rm, что немедленно удалит JPGфайлы.

Я написал следующий скрипт Python . По сравнению со скриптом ttaveira , он выполняет дополнительную работу.

  • Ищет в подкаталогах.
  • Создает целевой каталог отходов.
  • Удаляет файлы, которые уже существуют в ненужном каталоге, чтобы избежать ошибок перемещения.

# Script:      remove_jpg_if_raw_exists.py
#
# Description: This script looks in all sub directories for
#              pairs of JPG and RAW files.
#              For each pair found the JPG is moved to a
#              waste basket directory.
#              Otherwise JPG is kept.
#
# Author:      Thomas Dahlmann

import os, fnmatch

# define your file extensions here, case is ignored
raw_extension = "nef"
jpg_extension = "jpg"

# define waste basket directory here
waste_dir = "c:\image_waste_basked"

##### do not modify below ##########

# recursive find files 
def locate(pattern, root=os.curdir):
    '''Locate all files matching supplied filename pattern 
    in and below root directory.'''
    for path, dirs, files in os.walk(os.path.abspath(root)):
        for filename in fnmatch.filter(files, pattern):
            yield os.path.join(path, filename) 

# get base names from raw's
raw_hash = {}
for raw in locate("*." + raw_extension):
    base_name = os.path.basename(raw)
    base_name = os.path.splitext(base_name)[0]
    raw_hash[base_name] = True

# make waste basket dir
if not os.path.exists(waste_dir):
    os.makedirs(waste_dir)

# find pairs and move jpgs of pairs to waste basket    
for jpg in locate("*." + jpg_extension):
    base_name = os.path.basename(jpg)
    base_name = os.path.splitext(base_name)[0]
    if base_name in raw_hash:
        jpg_base_name_with_ext = base_name + "." + jpg_extension
        new_jpg = waste_dir + "\\" + jpg_base_name_with_ext
        print "%s => %s" % (jpg, waste_dir)
        if os.path.exists(new_jpg):
            os.remove(jpg)
        else:
            os.rename(jpg, new_jpg)
Привет и добро пожаловать на Photo.SE. Чем ваш ответ отличается от ответа Ттавейры ?
Сценарий выполняет некоторую дополнительную работу: также просматривает все подкаталоги, создает целевой каталог отходов для jpg, если он не существует, и удаляет jpg вместо перемещения, если он уже существует в каталоге отходов (избегает ошибок перемещения)

Работая над Mac OS X , в предыдущих ответах мне не хватало проверки работоспособности для «того же контента». У меня были повторяющиеся имена для разных изображений, потому что я забыл включить счетчик изображений в своей камере. Вот моя версия, которая проверяет информацию EXIF ​​для того же времени захвата:

Вам нужно бежать

sudo port install rmtrash exiv2

прежде чем вы сможете использовать следующую команду. Написано для сравнения JPGс NEFфайлами от моего Nikon D90. Настройте расширения файлов в соответствии с вашими потребностями.

find . -name \*.NEF |sed s/\.NEF/.JPG/g | xargs find 2>/dev/null | \
xargs perl -e 'foreach(@ARGV) {my $jpg=$_;my $nef=s/\.JPG/.NEF/r; my $tjpg = `exiv2 -g Exif.Photo.DateTimeOriginal -pt $jpg`; my $nef=s/\.JPG/.NEF/r; my $tnef = `exiv2 -g Exif.Photo.DateTimeOriginal -pt $nef`; if($tjpg eq $tnef) {print "$jpg\n"}}' | \
xargs rmtrash

без проверки работоспособности все это превратилось бы в очень короткую строчку:

find . -name \*.NEF |sed s/\.NEF/.JPG/g | xargs find 2>/dev/null | xargs rmtrash