Как переименовать файл по дате его создания и значению хеш-функции, чтобы получить уникальное имя файла?

find. -type f \( -name '*.sh' -o -name '*.md' \)

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

Чтобы сделать это более гибким:

suffixfind () (
    dir=$1
    shift

    for suf do
        set -- "$@" -o -name "*.$suf"
        shift
    done
    shift

    find "$dir" -type f \( "$@" \)
)

Эта вспомогательная функция оболочки (, которая будет работать в любойsh-подобной оболочке ), выберет первый аргумент командной строки и поместит его в переменную dir. Затем он создаст список -name "*.<suf1>" -o -name "*.<suf2>" (etc.)со всеми суффиксами имен файлов в командной строке функции перед вызовом findс этим списком для поиска файлов в $dirили ниже.

Вы бы использовали его как

suffixfind /usr sh md txt

, чтобы найти все обычные файлы с именами, заканчивающимися на .sh, .mdили .txtв пути /usrили под ним.

Несколько более подробный вариант вышеприведенного с использованием bashмассивов и bashлокальных переменных:

suffixfind () {
    local dir=$1
    shift

    local names

    names=( -name "*.$1" )
    shift
    for suf do
        names+=( -o -name "*.$suf" )
    done

    find "$dir" -type f \( "${names[@]}" \)
}

О вашем упоминании инструментов GNU и переносимости :Обратите внимание, что инструменты GNU в системах, отличных от -Linux, иногда доступны, но с префиксом gк именам инструментов. Таким образом, GNU findбудет доступен как gfind, чтобы отличить его от собственной реализации findв системе.

Таким образом, ваш "переносимый GNU" подход должен был бы проверить, доступен ли gfind, прежде чем проверять, действительно ли findявляется GNU find. Только после того, как вы сделаете это (, возможно, проверив статус возврата и вывод find --version), вы не сможете быть уверены, что имеете дело с GNU find.

1
10.01.2021, 23:36
2 ответа

То, как вы это делаете, работает crc32со всеми файлами одновременно, создавая одну строку со всеми контрольными суммами и именами файлов. Это строка, на которую жалуется mv.

Итак, запустите crc32 внутри цикла. Предполагая, что ваши файлы находятся в подкаталогах текущего каталога (, то есть ./dir0001/DCIM_0000.JPG, ./dir0002/DCIM_0123.JPGили что-то в этом роде ), и вы хотите поместить их вdestdir/:

#!/bin/bash
shopt -s globstar
for file in **/*.JPG; do
    crc=$(crc32 "$file")
    date=$(exiftool -d "%Y%m%d-%H%M%S" -CreateDate "$file" | awk '{print $4}')
    basename=$(basename "$file".JPG)            # remove directory and extension
    newname="destdir/$basename-$date-$crc.jpg"   # piece together a new name
    echo mv -nv "$file" "$newname"
done

**— это нестандартное расширение, которое запускает glob для всего дерева каталогов. Вы также можете использовать */*.JPGдля поиска файлов в ближайших подкаталогах.

Аналогично $date, вы можете добавить еще одну переменную для доли секунды и включить ее в то, как формируется newname:

subsec=$(exiftool -d "%Y%m%d-%H%M%S" -SubSecTimeDigitized "$file" | awk '{print $4}')
newname="destination/$basename-$date-$subsec-$crc.jpg"

Или что-то в этом роде. Проверьте вывод ваших файлов.

Удалите echoиз mv, как только убедитесь, что скрипт работает правильно.

2
18.03.2021, 22:37

Думаю, это могло бы сработать, по крайней мере, в моих тестах, если я правильно понимаю:

c=$(($(ls /target/dir | wc -l)+1))
for i in *.JPG; do 
  mv "$i" "/target/dir/$c.JPG"
  ((++c))
done

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

1.JPG
2.JPG
3.JPG

Запустите команду еще раз из другого каталога, теперь счетчик будет равен 4, поэтому результат будет:

1.JPG
2.JPG
3.JPG
4.JPG
5.JPG
6.JPG
...
0
18.03.2021, 22:37

Теги

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