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