Jak usunąć pliki JPG, ale tylko jeśli istnieje zgodny plik RAW?

18

Moje wczesne zdjęcia (Canon G2) to JPG, ale kiedy dostałem Nikona D90, początkowo zrobiłem zdjęcie w JPG, potem przełączyłem się na RAW + JPG, a teraz chciałbym przejść tylko na RAW.

Na dysku twardym mam dosłownie tysiące zdjęć. Zdjęcia znajdują się w podkatalogach (według daty) w jednym katalogu o nazwie Import.

Mam zamiar zaimportować wszystkie te zdjęcia do Lightroom 3.0, jednak chciałbym usunąć wszystkie pliki JPG, ale tylko tam, gdzie jest już odpowiedni plik RAW (tj. Nie chcę już zachować tych samych wersji JPG i RAW plik).

Jeśli mogę to zrobić łatwo w Lightroomie (po zaimportowaniu wszystkiego, w tym duplikatów plików JPG), byłoby świetnie. Byłoby również OK, gdyby istniał prosty sposób na to przed zaimportowaniem plików (ale mam nadzieję, że nie wymagałoby to odwiedzania każdego katalogu w poszukiwaniu nazw plików z rozszerzeniami JPG i NEF).

Czy ktoś wie, jak to zrobić (w Lightroom lub za pomocą jakiegoś narzędzia / skryptu w Windows)?

seanmc
źródło
Czy wszystkie pliki jpg i RAW mają co najmniej taki sam ciąg znaków (do każdego z nich można dodać inne znaki)? Np. IMG_1234_portrait_picture.jpg i IMG_1234.CR2.
dpollitt
Myślę, że wszystkie moje pary JPG / NEF mają dokładnie taką samą nazwę pliku (oprócz rozszerzenia).
seanmc
3
Głosuję za przeniesieniem tej opcji do Przepełnienia stosu, gdzie powinieneś uzyskać odpowiedź w ciągu kilku minut =)
anon
1
@anon: Jak dokładnie to należy do StackOverflow? Jest to zdecydowanie pytanie na ten temat, ponieważ dotyczy narzędzi do zarządzania obrazami i edycji zdjęć. Poza stycznym odniesieniem do skryptu ... nie ma to nic wspólnego z programowaniem.
jrista
2
Głosuję za zamknięciem tego pytania jako nie na temat, ponieważ tak naprawdę nie chodzi o fotografię, chodzi o zarządzanie plikami, które akurat są zdjęciami. Pytanie i odpowiedź byłyby takie same, gdyby dwa typy plików, o których mowa, były jakimikolwiek innymi typami plików, które mogłyby zostać przetłumaczone z jednej formy na drugą, np. Pliki doc i pdf, itp.
Xiota

Odpowiedzi:

24

W systemie Windows przejdź do folderu i uruchom to w wierszu polecenia:

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

Zasadniczo przegląda bieżący folder, przegląda pliki NEF i usuwa plik JPG, jeśli jest obecny. Ignoruje wszelkie błędy, jeśli JPG nie ma.

Jeśli chcesz podfoldery, dołącz /sdo dirpolecenia.

zaraz
źródło
3
Perfekcyjnie, dzięki! Oczywiście zanim uruchomiłem go po raz pierwszy, zmieniłem „del” na „echo”. Potem uruchomiłem „help for”, aby zrozumieć, co robi. Minęło sporo czasu, odkąd przyjrzałem się skryptom wiersza poleceń, ponieważ nie miałem pojęcia, że ​​polecenie „for” ma tak wiele opcji.
seanmc
Nie ma problemu! Podczas testowania użyłem również „echo” =) Aby zobaczyć więcej wyników, usuń „2> nul”. Chciałem zrobić coś takiego dla moich własnych plików NEF / JPG, i to była idealna okazja.
anon
7

Oto zmodyfikowana wersja skryptu Tomy's Python . Różnice:

  • dozwolone jest wiele nieprzetworzonych rozszerzeń
  • usuń jpg tylko wtedy, gdy pary znajdują się w tym samym folderze (unikaj przypadkowego usunięcia pliku jpg o nazwie jak plik raw w innym folderze)
  • wielkość liter nie ma znaczenia

#!/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)
Renaud B.
źródło
świetny scenariusz. Użyję go, ponieważ ma wiele dobrych przełączeń awaryjnych. Powinieneś jednak dodać tę linię #!/usr/bin/env pythonna początku. W przeciwnym razie miałem dziwne błędy ImageMagick (wydaje się, że mój Mac otwiera pliki .py z ImageMagick)
therealmarv
Po prostu FYI: wydaje się również, że nie działa, gdy pliki są naprawdę nazwane .jPg. Nie działa również, gdy pliki znajdują się na dysku zewnętrznym i marnują katalog, np. W katalogu /home.
therealmarv
@therealmarv: właściwie to, co dzieje się z ImageMagick, polega na tym, że skrypt jest otwierany w powłoce, a nie ImageMagick, ale „import” to nazwa narzędzia ImageMagick.
Max
6

Oto skrypt w języku Python, który przenosi JPGpliki, gdy nie RAWistnieje odpowiedni plik. Przydatne w 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)
ttaveira
źródło
5
  • Utwórz pustą bibliotekę
  • Z menu głównego Lightroom wybierz polecenie Edycja> Preferencje (Windows) lub Lightroom> Preferencje (Mac OS).
  • W preferencjach ogólnych odznacz „Traktuj pliki JPEG obok nieprzetworzonych plików jako oddzielne zdjęcia”
    • To powinno być domyślne.
  • Zaimportuj wszystkie swoje pliki (możesz wybrać podfoldery wyszukiwania), informując go o przeniesieniu do nowej lokalizacji
  • Pliki JPG zawierające pliki RAW zostaną pozostawione w oryginalnej lokalizacji do usunięcia

Jak rozumiem, miniatura w lightroomie może powiedzieć RAW + JPG, ale JPG nie jest w rzeczywistości przechowywany ani dostępny w jakikolwiek sposób.

Możesz także napisać całkiem prosty skrypt wsadowy w dowolnym języku programowania.

Eruditass
źródło
2

Podoba mi się skrypt bash dla OS X (autor: T.Toivonen ), ale zauważyłem, że jest kilka problemów.

  • Nie podobały mi się nazwy moich katalogów, które zawierają spacje. Wymagało to nieco innej obsługi polecenia find.

  • Oryginalny skrypt działa tylko dla rozszerzeń pisanych małymi literami. Nieznacznie poprawiłem tę część skryptu, aby uwzględnić również rozszerzenia, które są pisane wielkimi literami. Pamiętaj, że akceptuje tylko DNG+JPGlub dng+jpgparuje i zignoruje wszelkie kombinacje, takie jak DNG+jpglub DnG+JpG.

  • W oryginalnym rozwiązaniu zaproponowano tylko jedną wastedirlokalizację, natomiast moja poprawka pozwala na utworzenie podkatalogu w każdej gałęzi katalogu podczas podróży. Definiujesz nazwę katalogu przed pętlą.

  • Lubię widzieć, co się dzieje, szczególnie kiedy mvlub rmpolecenia są używane;)

Przez wzgląd na przestrzeni pokazuję tylko ostatnią część scenariusza, od ustawiania basedir, wastediri pętli.

[...]

#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
Filip Wolak
źródło
Pytanie oznaczono jako „Windows”, aby można było powiedzieć, jak można to zrobić w typowym systemie Windows. Na przykład korzystam z Cygwin (i planuję lepiej przyjrzeć się tej odpowiedzi, gdy jestem na komputerze, aby nieco zmienić zachowanie)
Chris H
2

Oto rozwiązanie dla bash(Linux lub Mac OS X). W systemie Windows możesz zainstalować Cygwin, aby uzyskać kopię 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
Ben Pingilley
źródło
2

Oto kolejna bashwersja używająca find(Linux). Podobnie jak w przypadku odpowiedzi Bena Pingilleya , możesz zainstalować Cygwin, aby uzyskać bash na Windowsie.

#!/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
bsod
źródło
1

Oto moje zdanie na ten temat. Wiele dobrych pomysłów pochodzi ze wspomnianych wcześniej skryptów.

Jest to skrypt bash dla OS X . Szuka plików, które istnieją z tą samą podstawową nazwą pliku i dng+jpgrozszerzeniami. Jeśli jpgznaleziono a o dokładnie takiej samej nazwie jak dng, wówczas nazwa pliku jest wyświetlana ( -e), plik jest przenoszony ( -m) lub usuwany ( -d).

Przejdzie przez podfoldery, dzięki czemu można go używać do całego katalogu lub tylko jego części.

W przypadku innych nieprzetworzonych rozszerzeń plików po prostu zamień *.dngw skrypcie preferowane rozszerzenie.

Ostrzeżenie: możesz mieć dwa różne obrazy o tej samej nazwie, ale z innym rozszerzeniem. To nieuniknione straty tego skryptu.

Oto jak korzystać ze skryptu:

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 

Podstawowe użycie będzie działać tak:

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

Powodowałoby to echo wszystkich nazw jpgplików, które spełniają kryteria posiadania obu plików dngi jpgplików o tej samej nazwie.

Wynik wyglądałby mniej więcej tak:

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.

Teraz jeśli chcę usunąć pliki Chciałbym tylko przełączyć -ena -d:

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

Lub jeśli chciałbym przenieść pliki do / duplikatów, wykonałbym to -m.

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

Teraz będą w nim duplikaty jpgplików/Volumes/photo/DNG/2015/duplicates

Oto skrypt: 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."
T. Toivonen
źródło
1

Oto bashscenariusz dla Mac OS X . To może działać na platformie Linux z pewnymi zmianami.

#!/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

rmtrashto narzędzie, które przenosi pliki do Kosza, zamiast ich natychmiastowego usuwania. Możesz go pobrać z MacPorts w ten sposób:

sudo port install rmtrash

Jeśli chcesz tego uniknąć, po prostu zamień rmtrashw skrypcie na rm, który natychmiast usunie JPGpliki.

Manas Tungare
źródło
1

Napisałem następujący skrypt w języku Python . W porównaniu ze skryptem ttaveira ma on dodatkową pracę.

  • Wygląda w podkatalogach.
  • Tworzy docelowy katalog odpadów.
  • Usuwa pliki, które już istnieją w katalogu odpadów, aby uniknąć błędów przenoszenia.

# 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)
Do mojego
źródło
2
Cześć i witamy na Photo.SE. Czym różni się twoja odpowiedź od odpowiedzi ttaveira ?
Saaru Lindestøkke
Skrypt wykonuje dodatkową pracę: przegląda również wszystkie podkatalogi, tworzy docelowy katalog odpadów dla plików JPG, jeśli nie istnieje i usuwa plik JPG zamiast przenoszenia, jeśli już istnieje w katalogu odpadów (pozwala uniknąć błędów przenoszenia)
Tomy
0

Pracując w systemie Mac OS X , w poprzednich odpowiedziach brakowało mi sprawdzenia poprawności „tej samej zawartości”. Miałem zduplikowane nazwy dla różnych zdjęć, ponieważ zapomniałem włączyć licznik obrazów w moim aparacie. Oto moja wersja, która sprawdza informacje EXIF ​​pod kątem tego samego czasu przechwytywania:

Musisz biec

sudo port install rmtrash exiv2

zanim będzie można użyć następującego polecenia. Został napisany w celu porównania JPGz NEFplikami z mojego Nikona D90. Dostosuj rozszerzenia plików do swoich potrzeb.

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

bez kontroli poczytalności całość stałaby się bardzo krótką linijką:

find . -name \*.NEF |sed s/\.NEF/.JPG/g | xargs find 2>/dev/null | xargs rmtrash
André Pareis
źródło