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
.
То, как вы это делаете, работает 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
, как только убедитесь, что скрипт работает правильно.
Думаю, это могло бы сработать, по крайней мере, в моих тестах, если я правильно понимаю:
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
...