Я читал довольно много сообщений о том, как найти файлы и скопировать их.
Чего хочу добиться. Копировать все *.jpg файлы из каждого каталога в один каталог. Чтобы избежать перезаписи, я намерен добавить или, скорее, вставить время эпохи в имя файла.
Из того, что я нашел до сих пор, наиболее успешным является следующий код:
find . -type f -name '*.jpg' -exec cp -T {} /media/hvdw/'Local station'/jpg/{}-$(date +%s) ;
Он отлично работает в одном каталоге, но как cp команда включает путь, я получаю следующую ошибку:
cp: cannot create regular file '/media/hvdw/Local station/jpg/./VXIMAGES/2999 03.jpg-1618003427': No such file or directory
- Вопрос первый: как я могу скопировать файл с пустым именем?
- Вопрос второй: как я могу вставить эпоху внутри имени файла и не добавлять ее к расширению? нравиться
2999 03-1618003427.jpg.
1 ответ
Как вы обнаружили, -exec заменители {} с полным путем, используемым find.
Вы хотите получить базовое имя (т.е. последний компонент имени пути), а затем вставить в него некоторую строку. Для этого вам понадобится оболочка «внутри». find.
Вы запускаете оболочку из find как это:
find … -exec sh -c '…' …
где аргумент в одинарных кавычках сразу после sh -c содержит код оболочки. Вы должны знать, как это сделать безопасно. Никогда не вставлять {} в коде оболочки. В вашем случае команда может быть такой:
find . -type f -name '*.jpg' -exec sh -c '…' find-sh {} ;
Примечание: find-sh объясняется здесь: Какая вторая шишка в sh -c 'some shell code' sh?
Теперь нам просто нужен правильный код оболочки, который будет манипулировать именем пути и вызывать cp. Этот мой ответ дает способ удалить некоторый суффикс, синтаксис будет похож на ${variable%.jpg} в нашем случае. Ссылки там ведут в места, где задокументирован синтаксис для удаления некоторого префикса. Мы будем использовать ${variable##*/} чтобы сначала получить базовое имя.
find . -type f -name '*.jpg' -exec sh -c '
file="$1"
newname="${file##*/}"
newname="${newname%.jpg}"
cp -T -- "$file" "/media/hvdw/Local station/jpg/$newname-$(date +%s).jpg"
' find-sh {} ;
Обратите внимание, что весь код оболочки заключен в одинарные кавычки, поэтому внешняя оболочка ничего не расширяет. В контексте внутренней оболочки некоторые вещи заключаются в двойные кавычки. как они должны быть.
Приведенный выше код запускает один sh и один cp на соответствующий файл. Мы можем улучшить производительность, уменьшив количество sh процессы. В следующем варианте используется -exec sh … {} + передать несколько имен пути sh:
find . -type f -name '*.jpg' -exec sh -c '
for file do
newname="${file##*/}"
newname="${newname%.jpg}"
cp -T -- "$file" "/media/hvdw/Local station/jpg/$newname-$(date +%s).jpg"
done
' find-sh {} +
Заключительные примечания:
- Достаточно быстро
cpвызовет вывод изdate +%sбыть неуникальным. На всякий случай рассмотримdate +%s.%Nесли твойdateподдерживает%N. -name '*.jpg'чувствителен к регистру и.jpgдважды жестко запрограммирован в нашем коде оболочки. Если вы каким-то образом разрешаете другие расширения (например, используя непереносимые, нечувствительные к регистру-iname '*.jpg'вместо этого) вам нужно будет улучшить код оболочки, чтобы обрабатывать заранее неизвестные расширения. Это возможно, но я не буду здесь вдаваться в подробности *.- Двойное тире в
cp -T -- "$file" …кажется ненужным, потому что расширенный$fileне может начинаться с-потому что это должно начинаться с.потому что мы использовалиfind . …. Но- очевидно, не все реализации
findработать так; - даже если твой
findделает, когда-нибудь вы можете захотеть использовать код сfind * …или так, то может получиться развернутое$fileначинается с-.
- очевидно, не все реализации
*) Вы или кто-либо другой можете задать отдельный вопрос, если это необходимо.
