Скопируйте только файлы, которые имеют аналогичные имена

Мой удар-fu не до задачи. Вы могли помочь мне? У меня есть папка, которая содержит:

viper.jpg
marshmallow.jpg
spider.jpg
cockroach.jpg
muffin.jpg
taffy.jpg

И папка, которая содержит

viper.doc
spider.doc
cockroach.doc

Я должен скопировать с папки 1 к папке 2 только соответствующих иллюстрации, для которых имена файлов соответствуют. Как?

2
задан 9 August 2018 в 00:10

5 ответов

С 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
2
ответ дан 2 December 2019 в 01:42

Очень простой с расширением параметра удара:

#!/bin/bash
cd folder2
for i in *; do
    cp "../folder1/${i%.*}.jpg" .
done

Пробелы дескрипторов, новые строки, и безотносительно других странных символов Вы бросаете в него.

Кроме того, если у Вас есть больше типов файлов, чем .jpg, который Вы хотите скопировать, можно заменить cp команда выше с этим (отмечают финал * выходит за пределы кавычек):

    cp "../folder1/${i%.*}."* .

Если у Вас есть файлы с несколькими расширениями (такой как .tar.gz) и Вы хотите разделить их всех, измениться % кому: %%.

3
ответ дан 2 December 2019 в 01:42

Никакая потребность в цикле, старом добром 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
0
ответ дан 2 December 2019 в 01:42

Вот забавный:

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.
  • если после всех выходов оболочки обычно со статусом выхода 0, это означает, что имя файла существует в целевом каталоге, и мы можем прибежать вторыми -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. Это могло бы быть длинным и окольным путем, но может быть довольно гибко.

1
ответ дан 2 December 2019 в 01:42

Это имеет несколько хороших функций:

  • Подкаталоги дескрипторов (например, src/a/b/c/d/e.jpg копируется в dst/a/b/c/d/e.jpg когда dst/a/b/c/d/e.doc существует),
  • Шоу, что это копирует, когда это идет
  • Суффиксы имени файла использования, а не расширения файла для обработки точек в именах файлов отлично независимо от того, сколько точек находится в имени файла или желаемом суффиксе
  • Каталоги и суффиксы не являются hardcoded в сценарии, таким образом, намного легче снова использовать сценарий для других целей
  • Дескрипторы все символы правильно, включая весь пробел и весь шарик и regex метасимволы
  • Запущение скрипта без аргументов дает короткий пример использования на основе этого вопроса

Это было упрощено значительно с помощью "ссылки" расширения параметра удара 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"
' \;
0
ответ дан 2 December 2019 в 01:42

Другие вопросы по тегам:

Похожие вопросы: