Перемещение имени файла с несколькими расширениями в другой каталог
#!/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