Перемещение имени файла с несколькими расширениями в другой каталог

#!/bin/bash
# script to find and move files

SOURCE=/DRIVE2/folder/
DESTDIR=/DRIVE/new3/

MOVEFILES=(mpg avi m4v mp4 3gp mpeg MOV) 
# this line above is not working, its only reading the first extension

find $SOURCE -type f -name *.$MOVEFILES -print | xargs -i mv -v "{}" $DESTDIR 

Ребята, можете ли вы помочь мне с моим сценарием Bash? $MOVEFILES часть моего сценария не работает. Он читает только первое добавленное мной расширение, которое mpg, Остальное игнорируется. Как правильно написать эту строку?

Также можно включить каталог, скажем, от/DRIVE2/folder1/folder2/folder3/folder4/file.ext перейти к /DRIVE/folder3/folder4/file.ext

4 ответа

Решение

С помощью find с -regex

MOVEFILES=".*\.\(mpg\|avi\|m4v\)"
find "$SOURCE" -type f -regex "$MOVEFILES" -exec mv {} "$DESTDIR" \;

Вы также можете использовать -iregex вместо -regex для нечувствительных к регистру совпадений, таких как AvI и так далее.

Все \ выглядит некрасиво, я знаю. -regextype posix-extended, как используется в ответе @Murus, выглядит лучше.

Вы, вероятно, должны использовать -regex вместо -name - с -nameкаждому расширению понадобится отдельный -name тестовое задание:

find .. -name '*.mp4' -name '*.avi' ...

Вместо:

find -regextype posix-extended ... -regex '.*\.(mp4|avi|...)' ...

Учитывая ваш массив, делайте (исключая ненужные xargs):

find "$SOURCE" -regextype posix-extended  -type f -regex ".*\.($(IFS="|"; echo "${MOVEFILES[*]}"))" -exec mv -t "$DESTDIR" {} +

IFS="|"; echo "${MOVEFILES[*]}" это способ напечатать каждый элемент в MOVEFILES массив разделен |,

$MOVEFILES сам по себе является лишь первым элементом в MOVEFILES массив.

Вы можете сделать это, используя только оболочку (bash):

shopt -s extglob globstar nullglob 
mv -t /destination **/*(*.mpg|*.m4v|*.mpeg|*.mp4|*.avi|*.3gp|*.MOV)
  • Сначала нам нужно установить несколько параметров оболочки

  • extglob позволит нам сделать расширенное сопоставление с образцом для имен файлов

  • globstar, после включения этого, используя ** мы можем перемещаться по подкаталогам для поиска файлов

  • nullglob приведет к пустой строке, если ни одно имя файла не соответствует нашим данным шаблонам, а не самим шаблонам

  • Сейчас, *(*.foo|*.bar) это extglob шаблон, который будет соответствовать нулю или более вхождений либо *.foo или же *.bar

  • Так в совокупности **/*(*.mpg|*.m4v|*.mpeg|*.mp4|*.avi|*.3gp|*.MOV) получит нам файлы для перемещения

  • mv -t /destination **/*(*.mpg|*.m4v|*.mpeg|*.mp4|*.avi|*.3gp|*.MOV) переместит файлы в /destination,

Пример:

$ tree 
.
├── dest
├── foo
│   ├── bar
│   │   ├── baz.md
│   │   ├── egg.3gp
│   │   └── egg.mp4
│   ├── baz.txt
│   ├── spam.avi
│   └── spam.mp3
├── spamegg.MOV
└── spamegg.txt


$ shopt -s extglob globstar nullglob 

$ mv -t dest/ **/*(*.mp3|*.mp4|*.avi|*.3gp|*.MOV)

$ tree 
.
├── dest
│   ├── egg.3gp
│   ├── egg.mp4
│   ├── spam.avi
│   ├── spamegg.MOV
│   └── spam.mp3
├── foo
│   ├── bar
│   │   └── baz.md
│   └── baz.txt
└── spamegg.txt

find Команда позволяет установить несколько условий с -o флаг, и вам не нужно xargs, ты можешь использовать -exec, Лично я бы изменил ваш сценарий на

#!/bin/bash
# script to find and move files

SOURCE=/DRIVE2/folder/
DESTDIR=/DRIVE/new3/


find "$SOURCE" -type f \( -name -o "*.mpg" -o -name "*.avi" -o -name "*.m4v" -o -name "*.mp4" -o -name "*.3gp"  -o -name "*.mpeg" -o -name "*.MOV" \) -exec mv -t "$DESTDIR" {} +

Другой подход был бы с циклом for, где мы работаем над каждым расширением индивидуально

for EXT in ${MOVEFILES[@]}; do find "$SOURCE" -type f -name "*.$EXT" -exec mv -t "$DESTDIR" {} +   ; done
Другие вопросы по тегам