Мой удар-fu не до задачи. Вы могли помочь мне? У меня есть папка, которая содержит:
viper.jpg
marshmallow.jpg
spider.jpg
cockroach.jpg
muffin.jpg
taffy.jpg
И папка, которая содержит
viper.doc
spider.doc
cockroach.doc
Я должен скопировать с папки 1 к папке 2 только соответствующих иллюстрации, для которых имена файлов соответствуют. Как?
С find
и оболочка (POSIX sh/bash/Korn/zsh) расширение параметра.
find /absolute/path/to/dIR2 -type f -name '*.doc' -execdir sh -c '
echo cp /absolute/path/to/dIR1/${0%.doc}.jpg .
' {} \;
cp /absolute/path/to/dIR1/./cockroach.jpg .
cp /absolute/path/to/dIR1/./spider.jpg .
cp /absolute/path/to/dIR1/./viper.jpg .
Где:
.
├── dIR1
│ ├── cockroach.jpg
│ ├── marshmallow.jpg
│ ├── muffin.jpg
│ ├── spider.jpg
│ ├── taffy.jpg
│ └── viper.jpg
└── dIR2
├── cockroach.doc
├── spider.doc
└── viper.doc
результат (удаляют echo
перед cp
выполнить копию на файлах):
.
├── dIR1
│ ├── cockroach.jpg
│ ├── marshmallow.jpg
│ ├── muffin.jpg
│ ├── spider.jpg
│ ├── taffy.jpg
│ └── viper.jpg
└── dIR2
├── cockroach.doc
├── cockroach.jpg
├── spider.doc
├── spider.jpg
├── viper.doc
└── viper.jpg
Предотвратить вызов cp
для каждого файлы нашли, мы можем использовать команду в качестве после пути:
find /absolute/path/to/dIR2 -type f -name '*.doc' -execdir bash -c '
printf "/absolute/path/to/dIR1/%s.jpg\0" "$'{@%.doc}'"' _ {} + \
| xargs -0 cp -t /absolute/path/to/dIR2
Очень простой с расширением параметра удара:
#!/bin/bash
cd folder2
for i in *; do
cp "../folder1/${i%.*}.jpg" .
done
Пробелы дескрипторов, новые строки, и безотносительно других странных символов Вы бросаете в него.
Кроме того, если у Вас есть больше типов файлов, чем .jpg, который Вы хотите скопировать, можно заменить cp
команда выше с этим (отмечают финал *
выходит за пределы кавычек):
cp "../folder1/${i%.*}."* .
Если у Вас есть файлы с несколькими расширениями (такой как .tar.gz
) и Вы хотите разделить их всех, измениться %
кому: %%
.
Никакая потребность в цикле, старом добром globbing.
# assuming we are directory above folder{1,2}
# also assume no spaces in file names
# real file names don't have spaces :p
cd folder2
F=$(echo * | sed -e 's/\.doc/\.\*/g')
cd ../folder1 && cp $F ../folder2
Вот забавный:
find ./f1 -type f -exec sh -c 'bn=$(basename -s ".jpg" "$1");test -f "$2"/"$bn".doc || exit 1' sh {} ./f2 \; -and -exec echo cp {} ./f2 \;
Или с добавлением отступа как сценарий:
#!/bin/bash
find "$1" -type f -exec sh -c '
bn=$(basename -s ".jpg" "$1");
test -f "$2"/"$bn".doc || exit 1' sh {} "$2" \; \
-and -exec echo cp {} "$2" \;
Перепутанный уже? Это на самом деле очень просто:
find
пересечет каталог, данный $1
переменная и только ищет объекты типа f, который является "регулярным файлом".
для каждого файла мы имеем два -exec
вызовы, с которыми присоединяются -and
флаг, какое желание выполнит второе -exec
только если сначала успешно выполняется, отчасти как &&
делает в сценариях оболочки.
Сначала exec
выполняет функцию и извлечение базового имени файла с разделением .jpeg
расширение, которое все сделано в экземпляре /bin/sh
названный с -c
флаг. Оболочки, названные с -c
отметьте помещают первый позиционный параметр в переменную $0
, который является, почему первый позиционный параметр должен быть sh
. После этого {}
файл, в настоящее время обрабатываемый, и "$2
будет каталог, где Вы хотите проверить дубликаты, который является folder 2
от примера OP.
bn=$(basename -s ".jpg" "$1")
основа извлечений и полосы расширение из в настоящее время обрабатываемого файла, таким образом если мы имеем ./f1/foo.jpg
будучи обработанным, результат foo
сохраненный в bn
переменная. test -f "$2"/"$bn".doc || exit 1
проверит, существует ли то же базовое имя, но с .doc расширением в целевом каталоге, и если не - возвратит статус выхода 1, который предотвращает второе -exec
быть выполненным find
.-exec
который является echo cp {} ./f2 \;
Примечание: удалить echo
часть для фактического копирования для происхождения, echo
до cp
для тестирования только так, чтобы можно было удостовериться, что Вы копируете только вещи, которые должны быть скопированы и обычно являются хорошей практикой.Так, со структурой каталогов как так:
$ tree
.
├── dir 1
│ ├── bar.jpg
│ └── foo.jpg
├── findbasenames.sh
└── top dir
└── dir 2
└── foo.doc
Вы видите, что существует foo.jpg
и foo.doc
. Запущение скрипта мы добираемся:
$ ./findbasenames.sh 'dir 1'/ ./top\ dir/dir\ 2/
cp dir 1/foo.jpg dir 1/
Как Вы видите, соглашения о сценарии с каталогами, которые содержат пробелы на их имя, несколько уровней каталогов (таким образом, Вы не должны cd
где угодно), и find
является рекурсивным, если Вам когда-нибудь нужно это для нахождения дублирующихся базовых имен в нескольких каталогах, хотя с -maxdepth 1
флаг можно сказать find
работать только через файлы в текущем каталоге. Плюс это должен обработать трудные имена файлов, такой как -foo.doc
. Это могло бы быть длинным и окольным путем, но может быть довольно гибко.
Это имеет несколько хороших функций:
src/a/b/c/d/e.jpg
копируется в dst/a/b/c/d/e.jpg
когда dst/a/b/c/d/e.doc
существует),Это было упрощено значительно с помощью "ссылки" расширения параметра удара Joseph Sible и идеи использовать сценарий оболочки в find -exec
из ответов αғsнιη и Sergiy Kolodyazhnyy.
#!/bin/bash
[ "$#" -ne "4" ] && printf 'Usage: "%s" [source-directory] [source-file-suffix] [destination-directory] [destination-file-suffix]\nExample: "%s" pictures .jpg documents .doc\n' "$0" "$0" && exit 1
[ ! -d "$1" ] && echo '"'"$1"'" is not a directory!' && exit 2
[ ! -d "$3" ] && echo '"'"$3"'" is not a directory!' && exit 3
export srcdir="$1" srcsuf="$2" dstdir="$3" dstsuf="$4" dstsufglob="$( sed 's/./\\&/g' <<< "$4" )"
# Turn off fnmatch(3)'s strange options so that find(1)'s `-name` argument works normally
unset FNM_NOESCAPE FNM_PATHNAME FNM_PERIOD FNM_FILE_NAME FNM_LEADING_DIR FNM_CASEFOLD
find "$dstdir" -type f -name '*'"$dstsufglob" -exec bash -c '
dst="{}"
dst="${dst%$dstsuf}$srcsuf"
src="${dst#$dstdir}"
src="$srcdir/${src#/}"
[ -f "$src" ] && cp -v "$src" "$dst"
' \;