Поиск дубликатов имен файлов в иерархии папок?

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

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

Например, изображения background.png и background.gif не будут разрешены, потому что, хотя у них разные расширения, они все равно имеют одинаковое имя файла.

Так что мне интересно, могу ли я сделать рекурсивный поиск в папке img, чтобы найти список файлов, которые имеют одно и то же имя (исключая расширение).

Есть ли команда, которая может это сделать?

22
задан 13 June 2011 в 20:28

51 ответ

Сохраните это в файле с именем duplicates.py

#!/usr/bin/env python # Syntax: duplicates.py DIRECTORY import os, sys top = sys.argv[1] d = {} for root, dirs, files in os.walk(top, topdown=False): for name in files: fn = os.path.join(root, name) basename, extension = os.path.splitext(name) basename = basename.lower() # ignore case if basename in d: print(d[basename]) print(fn) else: d[basename] = fn

Затем сделайте исполняемый файл:

chmod +x duplicates.py

Запустите, например. например:

./duplicates.py ~/images

Он должен выводить пары файлов, имеющих одинаковое базовое имя (1). Написанный на python, вы сможете изменить его.

5
ответ дан 4 August 2018 в 19:17
find . -mindepth 1 -printf '%h %f\n' | sort -t ' ' -k 2,2 | uniq -f 1 --all-repeated=separate | tr ' ' '/'

Как говорится в комментарии, это также найдет папки. Вот команда ограничить его файлами:

find . -mindepth 1 -type f -printf '%p %f\n' | ...
26
ответ дан 4 August 2018 в 19:17
  • 1
    Это путь Linux. Однако это также соответствует папкам – glebm 17 October 2012 в 01:01
  • 2
    Обновлен ответ на исключение каталогов. Спасибо за ваш комментарий. – ojblass 13 October 2014 в 17:28
  • 3
    Я изменил решение так, чтобы он возвращал полный (относительный) путь для всех дубликатов. К сожалению, он предполагает, что имена путей не содержат пробелов, потому что uniq не предоставляет функции для выбора другого разделителя поля. – David Foerster 16 August 2017 в 22:39
  • 4
    @DavidFoerster, ваш rev 6 был улучшением, но в отношении вашего комментария там, с тех пор, когда sed устарел? Arcane? Конечно. Вышло из употребления? Не то чтобы я знал. (И я только что проверил.) – cp.engr 13 October 2017 в 17:43
  • 5
    @ cp.engr: sed не устарел. Это обращение стало устаревшим после очередной смены. – David Foerster 14 October 2017 в 01:29

Я предполагаю, что вам нужно только увидеть эти «дубликаты», а затем обработать их вручную. Если это так, этот код bash4 должен делать то, что вы хотите, я думаю.

declare -A array=() dupes=() while IFS= read -r -d '' file; do base=${file##*/} base=${base%.*} if [[ ${array[$base]} ]]; then dupes[$base]+=" $file" else array[$base]=$file fi done < <(find /the/dir -type f -print0) for key in "${!dupes[@]}"; do echo "$key: ${array[$key]}${dupes[$key]}" done

См. Http://mywiki.wooledge.org/BashGuide/Arrays#Associative_Arrays и / или руководство bash для получения справки по синтаксис ассоциативного массива.

3
ответ дан 4 August 2018 в 19:17
  • 1
    Как выполнить такую ​​команду в терминале? Это что-то мне нужно сначала сохранить в файл и выполнить файл? – JD Isaacks 14 June 2011 в 00:35
  • 2
    @John Isaacks Вы можете скопировать / вставить его в терминал, или вы можете поместить его в файл и запустить его как скрипт. Любой случай достигнет того же. – geirha 14 June 2011 в 01:21

Это bname:

#!/bin/bash # # find for jpg/png/gif more files of same basename # # echo "processing ($1) $2" bname=$(basename "$1" .$2) find -name "$bname.jpg" -or -name "$bname.png"

Сделайте его исполняемым:

chmod a+x bname

Вызовите его:

for ext in jpg png jpeg gif tiff; do find -name "*.$ext" -exec ./bname "{}" $ext ";" ; done

Pro:

Это простой и простой, поэтому расширяемый. Обрабатывает пробелы, вкладки, строки и файлы в именах файлов, afaik. (Предполагая, что в имени расширения нет такой вещи).

Con:

Это просто и просто, поэтому расширяемость.
1
ответ дан 4 August 2018 в 19:17

Сохраните это в файле с именем duplicates.py

#!/usr/bin/env python # Syntax: duplicates.py DIRECTORY import os, sys top = sys.argv[1] d = {} for root, dirs, files in os.walk(top, topdown=False): for name in files: fn = os.path.join(root, name) basename, extension = os.path.splitext(name) basename = basename.lower() # ignore case if basename in d: print(d[basename]) print(fn) else: d[basename] = fn

Затем сделайте исполняемый файл:

chmod +x duplicates.py

Запустите, например. например:

./duplicates.py ~/images

Он должен выводить пары файлов, имеющих одинаковое базовое имя (1). Написанный на python, вы сможете изменить его.

5
ответ дан 6 August 2018 в 03:30
find . -mindepth 1 -printf '%h %f\n' | sort -t ' ' -k 2,2 | uniq -f 1 --all-repeated=separate | tr ' ' '/'

Как говорится в комментарии, это также найдет папки. Вот команда ограничить его файлами:

find . -mindepth 1 -type f -printf '%p %f\n' | ...
26
ответ дан 6 August 2018 в 03:30
  • 1
    Это путь Linux. Однако это также соответствует папкам – glebm 17 October 2012 в 01:01
  • 2
    Обновлен ответ на исключение каталогов. Спасибо за ваш комментарий. – ojblass 13 October 2014 в 17:28
  • 3
    Я изменил решение так, чтобы он возвращал полный (относительный) путь для всех дубликатов. К сожалению, он предполагает, что имена путей не содержат пробелов, потому что uniq не предоставляет функции для выбора другого разделителя поля. – David Foerster 16 August 2017 в 22:39
  • 4
    @DavidFoerster, ваш rev 6 был улучшением, но в отношении вашего комментария там, с тех пор, когда sed устарел? Arcane? Конечно. Вышло из употребления? Не то чтобы я знал. (И я только что проверил.) – cp.engr 13 October 2017 в 17:43
  • 5
    @ cp.engr: sed не устарел. Это обращение стало устаревшим после очередной смены. – David Foerster 14 October 2017 в 01:29

Я предполагаю, что вам нужно только увидеть эти «дубликаты», а затем обработать их вручную. Если это так, этот код bash4 должен делать то, что вы хотите, я думаю.

declare -A array=() dupes=() while IFS= read -r -d '' file; do base=${file##*/} base=${base%.*} if [[ ${array[$base]} ]]; then dupes[$base]+=" $file" else array[$base]=$file fi done < <(find /the/dir -type f -print0) for key in "${!dupes[@]}"; do echo "$key: ${array[$key]}${dupes[$key]}" done

См. Http://mywiki.wooledge.org/BashGuide/Arrays#Associative_Arrays и / или руководство bash для получения справки по синтаксис ассоциативного массива.

3
ответ дан 6 August 2018 в 03:30
  • 1
    Как выполнить такую ​​команду в терминале? Это что-то мне нужно сначала сохранить в файл и выполнить файл? – JD Isaacks 14 June 2011 в 00:35
  • 2
    @John Isaacks Вы можете скопировать / вставить его в терминал, или вы можете поместить его в файл и запустить его как скрипт. Любой случай достигнет того же. – geirha 14 June 2011 в 01:21

Это bname:

#!/bin/bash # # find for jpg/png/gif more files of same basename # # echo "processing ($1) $2" bname=$(basename "$1" .$2) find -name "$bname.jpg" -or -name "$bname.png"

Сделайте его исполняемым:

chmod a+x bname

Вызовите его:

for ext in jpg png jpeg gif tiff; do find -name "*.$ext" -exec ./bname "{}" $ext ";" ; done

Pro:

Это простой и простой, поэтому расширяемый. Обрабатывает пробелы, вкладки, строки и файлы в именах файлов, afaik. (Предполагая, что в имени расширения нет такой вещи).

Con:

Это просто и просто, поэтому расширяемость.
1
ответ дан 6 August 2018 в 03:30

Сохраните это в файле с именем duplicates.py

#!/usr/bin/env python # Syntax: duplicates.py DIRECTORY import os, sys top = sys.argv[1] d = {} for root, dirs, files in os.walk(top, topdown=False): for name in files: fn = os.path.join(root, name) basename, extension = os.path.splitext(name) basename = basename.lower() # ignore case if basename in d: print(d[basename]) print(fn) else: d[basename] = fn

Затем сделайте исполняемый файл:

chmod +x duplicates.py

Запустите, например. например:

./duplicates.py ~/images

Он должен выводить пары файлов, имеющих одинаковое базовое имя (1). Написанный на python, вы сможете изменить его.

5
ответ дан 7 August 2018 в 21:17
find . -mindepth 1 -printf '%h %f\n' | sort -t ' ' -k 2,2 | uniq -f 1 --all-repeated=separate | tr ' ' '/'

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

find . -mindepth 1 -type f -printf '%p %f\n' | ...
26
ответ дан 7 August 2018 в 21:17
  • 1
    Это путь Linux. Однако это также соответствует папкам – glebm 17 October 2012 в 01:01
  • 2
    Обновлен ответ на исключение каталогов. Спасибо за ваш комментарий. – ojblass 13 October 2014 в 17:28
  • 3
    Я изменил решение так, чтобы он возвращал полный (относительный) путь для всех дубликатов. К сожалению, он предполагает, что имена путей не содержат пробелов, потому что uniq не предоставляет функции для выбора другого разделителя поля. – David Foerster 16 August 2017 в 22:39
  • 4
    @DavidFoerster, ваш rev 6 был улучшением, но в отношении вашего комментария там, с тех пор, когда sed устарел? Arcane? Конечно. Вышло из употребления? Не то чтобы я знал. (И я только что проверил.) – cp.engr 13 October 2017 в 17:43
  • 5
    @ cp.engr: sed не устарел. Это обращение стало устаревшим после очередной смены. – David Foerster 14 October 2017 в 01:29

Я предполагаю, что вам нужно только увидеть эти «дубликаты», а затем обработать их вручную. Если это так, этот код bash4 должен делать то, что вы хотите, я думаю.

declare -A array=() dupes=() while IFS= read -r -d '' file; do base=${file##*/} base=${base%.*} if [[ ${array[$base]} ]]; then dupes[$base]+=" $file" else array[$base]=$file fi done < <(find /the/dir -type f -print0) for key in "${!dupes[@]}"; do echo "$key: ${array[$key]}${dupes[$key]}" done

См. Http://mywiki.wooledge.org/BashGuide/Arrays#Associative_Arrays и / или руководство bash для получения справки по синтаксис ассоциативного массива.

3
ответ дан 7 August 2018 в 21:17
  • 1
    Как выполнить такую ​​команду в терминале? Это что-то мне нужно сначала сохранить в файл и выполнить файл? – JD Isaacks 14 June 2011 в 00:35
  • 2
    @John Isaacks Вы можете скопировать / вставить его в терминал, или вы можете поместить его в файл и запустить его как скрипт. Любой случай достигнет того же. – geirha 14 June 2011 в 01:21

это имя:

#!/bin/bash # # find for jpg/png/gif more files of same basename # # echo "processing ($1) $2" bname=$(basename "$1" .$2) find -name "$bname.jpg" -or -name "$bname.png"

сделайте его исполняемым:

chmod a+x bname

ссылаться на это:

for ext in jpg png jpeg gif tiff; do find -name "*.$ext" -exec ./bname "{}" $ext ";" ; done

плюсы:

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

минусы:

это просто и понятно, поэтому расширяемым.
1
ответ дан 7 August 2018 в 21:17

Сохраните это в файле с именем duplicates.py

  #! / usr / bin / env python # Синтаксис: duplicates.py Импорт каталога os, sys top  = sys.argv [1] d = {} для root, dirs, файлов в os.walk (top, topdown = False): для имени в файлах: fn = os.path.join (root, name) basename, extension =  os.path.splitext (name) basename = basename.lower () # игнорировать регистр, если basename в d: print (d [basename]) print (fn) else: d [basename] = fn  

Затем сделайте исполняемый файл:

  chmod + x duplicates.py  

Запустите, например, например:

  ./ duplicates.py ~ / images  

Он должен выводить пары файлов, имеющих одинаковое базовое имя (1). Написанный на python, вы сможете изменить его.

5
ответ дан 10 August 2018 в 09:36
  find.  -mindepth 1 -printf '% h% f \n' |  sort -t '' -k 2,2 |  uniq -f 1 - all-repeat = отдельный |  tr '' '/'  

Как говорится в комментарии, это также найдет папки. Вот команда ограничить его файлами:

  find.  -mindepth 1-type f -printf '% p% f \n' |  ...  
26
ответ дан 10 August 2018 в 09:36

Я предполагаю, что вам нужно только увидеть эти «дубликаты», а затем обработать их вручную. Если это так, этот код bash4 должен делать то, что вы хотите, я думаю.

  declare -A array = () dupes = (), в то время как IFS = read -r -d '' file;  do base = $ {file ## * /} base = $ {base%. *}, если [[$ {array [$ base]}]];  затем dupes [$ base] + = "$ file" else array [$ base] = $ file fi done & lt;  & lt; (find / the / dir -type f -print0) для ключа в "$ {! dupes [@]}";  do echo "$ key: $ {array [$ key]} $ {dupes [$ key]}" done  

См. http://mywiki.wooledge.org/BashGuide / Arrays # Associative_Arrays и / или справочник bash для справки по синтаксису ассоциативного массива.

3
ответ дан 10 August 2018 в 09:36

Это bname:

  #! / bin / bash # # find for jpg / png / gif больше файлов одного и того же basename # # echo "processing ($ 1) $ 2" bname = $  (basename "$ 1". $ 2) find -name "$ bname.jpg" -or -name "$ bname.png"  

Сделать его исполняемым:

  chmod a + x bname  

Вызвать это:

  для ext в jpg png jpeg gif tiff;  do find -name "*. $ ext" -exec ./bname "{}" $ ext ";"  ;   

Pro:

  • Прост и прост, поэтому расширяемый.
  • Обрабатывает пробелы, вкладки, строки и файлы в именах файлов, насколько мне известно.

Con:

  • Он всегда находит файл сам, и если он найдет a.gif для a.jpg, он найдет a.jpg для a.gif тоже. Таким образом, для 10 файлов одного и того же базового имени в конце концов найдено 100 совпадений.
1
ответ дан 10 August 2018 в 09:36

Это bname:

  #! / bin / bash # # find for jpg / png / gif больше файлов одного и того же basename # # echo "processing ($ 1) $ 2" bname = $  (basename "$ 1". $ 2) find -name "$ bname.jpg" -or -name "$ bname.png"  

Сделать его исполняемым:

  chmod a + x bname  

Вызвать это:

  для ext в jpg png jpeg gif tiff;  do find -name "*. $ ext" -exec ./bname "{}" $ ext ";"  ;   

Pro:

  • Прост и прост, поэтому расширяемый.
  • Обрабатывает пробелы, вкладки, строки и файлы в именах файлов, насколько мне известно.

Con:

  • Он всегда находит файл сам, и если он найдет a.gif для a.jpg, он найдет a.jpg для a.gif тоже. Таким образом, для 10 файлов одного и того же базового имени в конце концов найдено 100 совпадений.
1
ответ дан 13 August 2018 в 15:46
  find.  -mindepth 1 -printf '% h% f \n' |  sort -t '' -k 2,2 |  uniq -f 1 - all-repeat = отдельный |  tr '' '/'  

Как говорится в комментарии, это также найдет папки. Вот команда ограничить его файлами:

  find.  -mindepth 1-type f -printf '% p% f \n' |  ...  
26
ответ дан 13 August 2018 в 15:46
  • 1
    Это путь Linux. Однако это также соответствует папкам – glebm 17 October 2012 в 01:01
  • 2
    Обновлен ответ на исключение каталогов. Спасибо за ваш комментарий. – ojblass 13 October 2014 в 17:28
  • 3
    Я изменил решение так, чтобы он возвращал полный (относительный) путь для всех дубликатов. К сожалению, предполагается, что имена путей не содержат пробелов, потому что uniq не предоставляет функции для выбора другого разделителя полей. – David Foerster 16 August 2017 в 22:39
  • 4
    @DavidFoerster, ваш rev 6 был улучшением, но в отношении вашего комментария там, так как когда sed устарел? Arcane? Конечно. Вышло из употребления? Не то чтобы я знал. (И я только что проверил.) – cp.engr 13 October 2017 в 17:43
  • 5
    @ cp.engr: sed не устарел. Это обращение стало устаревшим после очередной смены. – David Foerster 14 October 2017 в 01:29
  • 6
    @DavidFoerster, устаревший, кажется, не подходит для меня. Я думаю, что "обрезано" было бы лучше. Независимо, спасибо за разъяснение. – cp.engr 14 October 2017 в 06:19
  • 7
    @ cp.engr: Спасибо за предложение! Я не знал этого слова, но, похоже, он лучше соответствовал ситуации. – David Foerster 14 October 2017 в 09:37

Я предполагаю, что вам нужно только увидеть эти «дубликаты», а затем обработать их вручную. Если это так, этот код bash4 должен делать то, что вы хотите, я думаю.

  declare -A array = () dupes = (), в то время как IFS = read -r -d '' file;  do base = $ {file ## * /} base = $ {base%. *}, если [[$ {array [$ base]}]];  затем dupes [$ base] + = "$ file" else array [$ base] = $ file fi done & lt;  & lt; (find / the / dir -type f -print0) для ключа в "$ {! dupes [@]}";  do echo "$ key: $ {array [$ key]} $ {dupes [$ key]}" done  

См. http://mywiki.wooledge.org/BashGuide / Arrays # Associative_Arrays и / или справочник bash для справки по синтаксису ассоциативного массива.

3
ответ дан 13 August 2018 в 15:46
  • 1
    Как выполнить такую ​​команду в терминале? Это что-то мне нужно сначала сохранить в файл и выполнить файл? – JD Isaacks 14 June 2011 в 00:35
  • 2
    @John Isaacks Вы можете скопировать / вставить его в терминал, или вы можете поместить его в файл и запустить его как скрипт. Любой случай достигнет того же. – geirha 14 June 2011 в 01:21

Сохраните это в файле с именем duplicates.py

  #! / usr / bin / env python # Синтаксис: duplicates.py Импорт каталога os, sys top  = sys.argv [1] d = {} для root, dirs, файлов в os.walk (top, topdown = False): для имени в файлах: fn = os.path.join (root, name) basename, extension =  os.path.splitext (name) basename = basename.lower () # игнорировать регистр, если basename в d: print (d [basename]) print (fn) else: d [basename] = fn  

Затем сделайте исполняемый файл:

  chmod + x duplicates.py  

Запустите, например, например:

  ./ duplicates.py ~ / images  

Он должен выводить пары файлов, имеющих одинаковое базовое имя (1). Написанный на python, вы сможете изменить его.

5
ответ дан 13 August 2018 в 15:46

Улучшение сценария loevborg для моих нужд (включает в себя сгруппированный вывод, черный список, более чистый вывод во время сканирования).

Использование:

python duplicates.py DIRNAME

duplicates.py

    #!/usr/bin/env python

    # Syntax: duplicates.py DIRECTORY

    import os
    import sys

    top = sys.argv[1]
    d = {}

    file_count = 0

    BLACKLIST = [".DS_Store", ]

    for root, dirs, files in os.walk(top, topdown=False):
        for name in files:
            file_count += 1
            fn = os.path.join(root, name)
            basename, extension = os.path.splitext(name)

            # Enable this if you want to ignore case.
            # basename = basename.lower()

            if basename not in BLACKLIST:
                sys.stdout.write(
                    "Scanning... %s files scanned.  Currently looking at ...%s/\r" %
                    (file_count, root[-50:])
                )

                if basename in d:
                    d[basename].append(fn)
                else:
                    d[basename] = [fn, ]

    print("\nDone scanning. Here are the duplicates found: ")

    for k, v in d.items():
        if len(v) > 1:
            print("%s (%s):" % (k, len(v)))
            for f in v:
                print (f)
python duplicates.py DIRNAME

duplicates.py

    #!/usr/bin/env python

    # Syntax: duplicates.py DIRECTORY

    import os
    import sys

    top = sys.argv[1]
    d = {}

    file_count = 0

    BLACKLIST = [".DS_Store", ]

    for root, dirs, files in os.walk(top, topdown=False):
        for name in files:
            file_count += 1
            fn = os.path.join(root, name)
            basename, extension = os.path.splitext(name)

            # Enable this if you want to ignore case.
            # basename = basename.lower()

            if basename not in BLACKLIST:
                sys.stdout.write(
                    "Scanning... %s files scanned.  Currently looking at ...%s/\r" %
                    (file_count, root[-50:])
                )

                if basename in d:
                    d[basename].append(fn)
                else:
                    d[basename] = [fn, ]

    print("\nDone scanning. Here are the duplicates found: ")

    for k, v in d.items():
        if len(v) > 1:
            print("%s (%s):" % (k, len(v)))
            for f in v:
                print (f)
]
0
ответ дан 9 October 2018 в 10:44

Другие вопросы по тегам:

Похожие вопросы: