найти и скопировать все изображения в каталоге с помощью терминала linux mint, пытаясь понять синтаксис

ОС Линукс Минт

Как говорится в заголовке, наконец, я хотел бы найти и скопировать все изображения в каталоге.

Я нашел:

найдите все файлы jpg (или JPG) в каталоге и скопируйте их в папку /home/joachim/neu2:

find . -iname \*.jpg -print0 | xargs -I{} -0 cp -v {} /home/joachim/neu2

и

найти все файлы изображений в каталоге:

find . -name '*' -exec file {} \; | grep -o -P '^.+: \w+ image' 

Моя проблема в том, что я не совсем понимаю синтаксис. Может ли кто-нибудь объяснить код?

А во-вторых, может ли кто-нибудь соединить два кода для генерации кода, который делает то, что я хочу;)

Приветствую и заранее благодарю!


person newandlost    schedule 16.06.2014    source источник


Ответы (4)


Во-первых, поймите, что труба | команды links передают вывод первой во вторую в качестве аргумента. Оба ваших шелл-кода направляют вывод команды find в другие команды (grep и xargs). Давайте рассмотрим эти команды одну за другой:

Первая команда: найти

find — это программа для поиска файлов в иерархии каталогов (это объяснение из справочной страницы find). Синтаксис (в данном случае)

find <search directory> <search pattern> <action>

В обоих случаях каталогом поиска является . (это текущий каталог). Обратите внимание, что он ищет не только в текущем каталоге, но и во всех его подкаталогах (иерархия каталогов).

Шаблон поиска принимает опции -name (это означает, что он ищет файлы, имя которых соответствует шаблону, заданному в качестве аргумента этой опции) или -iname (то же самое, что и имя, но без учета регистра) среди прочих.

Шаблон действия может быть -print0 (печатать точное имя файла, включая его позицию в заданном каталоге поиска, т. е. относительный или абсолютный путь к файлу) или -exec (выполнить данную команду над файлом (файлами), команда состоит в том, чтобы заканчиваться на ; и каждый экземпляр {} заменяется именем файла).

То есть первый шелл-код (первая часть слева от пайпа)

find . -iname \*.jpg -print0 

ищет все файлы с окончанием .jpg в текущей иерархии каталогов и печатает их пути и имена. Второй (первая часть)

find . -name '*' -exec file {} \; 

находит все файлы в текущей иерархии каталогов и выполняет

file <filename>

на них. Файл — это еще одна команда, которая определяет и печатает тип файла (подробности смотрите на справочной странице, справочный файл).

Вторая команда: xargs

xargs — это команда, которая создает и выполняет командные строки из стандартного ввода (man xargs), то есть из результатов поиска, которые передаются в xargs. Команда, которую он создает и выполняет, в этом случае

cp -v {} /home/joachim/neu2"

Опция -I{} определяет строку замены, т. е. каждый экземпляр {} в команде должен быть заменен входными данными, полученными из файла (то есть именами файлов). Опция -0 определяет, что элементы ввода не заканчиваются (разделяются) пробелом или новой строкой, а только нулевым символом. Это кажется необходимым при использовании стандартного способа поиска вывода в качестве ввода xargs.

Созданная и выполняемая команда — это, конечно же, команда копирования с опцией -v (многословная), и она копирует каждое из имен файлов, полученных из find, в каталог.

Третья команда: grep

grep фильтрует свой ввод, выдавая только те строки или строки, которые соответствуют определенному шаблону вывода. Опция -o указывает grep напечатать только совпадающую строку, а не всю строку (см. man grep), -P указывает интерпретировать следующий шаблон как шаблон регулярного выражения Perl. В регулярном выражении perl ^ — это начало строки, .+ — любая произвольная строка, за этой произвольной должна следовать двоеточие, пробел, количество буквенно-цифровых символов (в регулярном выражении perl обозначается \w+), пробел и строка изображение. По сути, эта команда grep фильтрует вывод файла, чтобы выводить только те имена файлов, которые являются файлами изображений. (Почитайте, например, о регулярных выражениях perl здесь: http://www.comp.leeds.ac.uk/Perl/matching.html )

Команда, которую вы действительно хотели

Теперь то, что вы хотите сделать, это (1) взять вывод второй команды оболочки (в которой перечислены файлы изображений), (2) привести его в соответствующую форму и (3) передать его в команду xargs из первой команды оболочки. line (которая затем создает и выполняет нужную команду копирования). Итак, на этот раз у нас есть команда оболочки из трех (на самом деле четырех) этапов с двумя конвейерами. Не проблема. У нас уже есть этапы (1) и (3) (хотя на этапе (3) нам нужно пропустить опцию -0, потому что входные данные больше не находят выход; нам нужно, чтобы новые строки рассматривались как разделители элементов).

Стадия (2) по-прежнему отсутствует. Я предлагаю использовать для этого команду cut. cut изменяет строки py, разделяя их на разные поля (разделенные символом-разделителем в исходной строке), которые затем можно переупорядочить. Я выберу : в качестве символа-разделителя (это завершает имя файла в выводе grep, опция -d':') и скажу, чтобы он давал нам только первое поле (опция -f1, Essentialls: печатать только имя файла, а не часть который следует за :), т. е. этап (2) будет тогда

cut -d':' -f1

И вся команда, которую вы хотели, будет:

find . -name '*' -exec file {} \; | grep -o -P '^.+: \w+ image' | cut -d':' -f1 | xargs -I{} cp -v {} /home/joachim/neu2

Обратите внимание, что вы можете найти все справочные страницы, например, здесь: http://www.linuxmanpages.com

person 0range    schedule 17.06.2014
comment
Большое спасибо!!! Ваш ответ содержит так много информации, которая действительно помогает мне лучше понять все это. - person newandlost; 19.06.2014
comment
И это безумие, как много нужно знать для понимания команд. - person newandlost; 19.06.2014
comment
Когда вы говорите ... или -exec (выполнить данную команду в файле (файлах), команда должна заканчиваться ;... вы на самом деле имеете в виду \; или почему есть \ ? - person newandlost; 19.06.2014
comment
\ — это escape-символ, который используется для того, чтобы избежать ; расширяется оболочкой (в этом случае оболочка будет интерпретировать это не как часть команды find, а как разделение двух команд, которые должны выполняться последовательно) - person 0range; 20.06.2014
comment
Просто хотел сказать: отличный подробный ответ, который побудил меня войти в систему, чтобы я мог проголосовать за вас. - person Andrioid; 15.11.2015
comment
Спасибо за этот ответ. Как я могу использовать это, чтобы сохранить изображение вместе с его текущей файловой структурой в новый каталог? - person Ryan Breece; 29.03.2018
comment
@ Райан Не понимаю, почему бы и нет. Вам просто нужно создать каталоги перед копированием изображений. Может быть, а может и не быть способа использовать больше каналов для интеграции этого в эту однострочную команду. Но обычно считается, что удобочитаемость имеет значение. Как следствие, я настоятельно рекомендую вместо этого написать сценарий bash с немного большей структурой. В любом случае это будет отдельный вопрос. - person 0range; 07.12.2018
comment
Вы сказали, что iname чувствителен к регистру... но в руководстве сказано: -iname pattern То же, что и -name, но совпадение нечувствительно к регистру. Например, шаблоны fo*' and F??' соответствуют именам файлов Foo', FOO', foo', fOo' и т. д. Шаблон *foo* также будет соответствовать имени файла '.foobar'. - person Mike Kormendy; 10.09.2020
comment
@MikeKormendy: Да, это была простая ошибка, спасибо. - person 0range; 14.09.2020

Я понял команду только с помощью awk, которая также выполняет эту работу:

find . -name '*' -exec file {} \; | 
awk '{
    if ($3=="image"){
        print substr($1, 0, length($1)-1);
        system("cp " substr($1, 0, length($1)-1) " /home/joachim/neu2" )
    }   
}'

substr($1, 0, length($1)-1) необходим, потому что в файле первого столбца возвращается имя;

person newandlost    schedule 19.06.2014

Приведенный выше ответ действительно хорош. но это может занять больше времени, если это огромный каталог. вот его более короткая версия, если вы уже знаете расширение своего файла

 find . -name \*.jpg | cut -d':' -f1 | xargs -I{} cp --parents -v {} ~/testimage/
person Shahin Khani    schedule 07.07.2015

Вот еще один, который работает как шарм. Он добавляет время EPOCH для предотвращения перезаписи файлов с тем же именем.

cd /media/myhome/'Local station'/
find . -path ./jpg -prune -o -type f -iname '*.jpg' -exec sh -c '
for file do
   newname="${file##*/}"
   newname="${newname%.jpg}"
   mv -T -- "$file" "/media/myhome/Local station/jpg/$newname-$(date +%s).jpg"
done
' find-sh {} +
cd  ~/

Он был разработан Камилом в этом сообщении. здесь.

person HvdW    schedule 14.04.2021