намерете и копирайте всички изображения в директорията с помощта на терминал linux mint, опитвайки се да разберете синтаксиса

OS 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)


Първо, разберете, че тръбата | свързва команди, предаващи изхода на първия във втория като аргумент. Вашите два шел кода препращат изхода на командата find в други команди (grep и xargs). Нека да разгледаме тези команди една след друга:

Първа команда: намери

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

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

И в двата случая директорията за търсене е . (това е текущата директория). Имайте предвид, че той не търси само в текущата директория, но и във всички нейни поддиректории (йерархията на директориите).

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

Моделът на действие може да бъде -print0 (отпечатва точното име на файла, включително позицията му в дадената директория за търсене, т.е. относителния или абсолютния път до файла) или -exec (изпълнява дадената команда върху файла(ите), командата е да завършва с ; и всяко копие на {} се заменя с името на файла).

Това е първият шел код (първата част, вляво от тръбата)

find . -iname \*.jpg -print0 

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

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

намира всички файлове в йерархията на текущата директория и се изпълнява

file <filename>

на тях. File е друга команда, която определя и отпечатва типа на файла (погледнете man страницата за подробности, man file).

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

xargs е команда, която изгражда и изпълнява командни редове от стандартен вход (man xargs), т.е. от изхода за намиране, който се предава в xargs. Командата, която изгражда и изпълнява, е в този случай

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

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

Командата, която се изгражда и изпълнява, разбира се, е командата за копиране с опция -v (подробно) и тя копира всяко от имената на файловете, които получава от find, в директорията.

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

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

Командата, която всъщност искахте

Сега това, което искате да направите, е (1) да вземете изхода от втората команда на обвивката (която изброява файловете с изображения), (2) да я пренесете в подходящата форма и (3) да я насочите към командата xargs от първата команда на обвивката линия (която след това изгражда и изпълнява командата за копиране, която искате). Така че този път имаме три (всъщност четири) етапна командна обвивка с две тръби. Не е проблем. Вече имаме етапи (1) и (3) (въпреки че в етап (3) трябва да оставим опцията -0, защото входът вече не е изход за намиране; имаме нужда от него, за да третираме новите редове като разделители на елементи).

Етап (2) все още липсва. Предлагам да използвате командата cut за това. cut променя низове py разделяйки ги на различни полета (разделени с разделителен знак в оригиналния низ), които след това могат да бъдат пренаредени. Ще избера : като знак за разделител (това завършва името на файла в изхода на grep, опция -d':') и ще му кажа да ни даде само първото поле (опция -f1, основни: отпечатайте само името на файла, а не частта който идва след :), т.е. етап (2) тогава ще бъде

cut -d':' -f1

И цялата команда, която искате, тогава ще бъде:

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

Обърнете внимание, че можете да намерите всички man страници например тук: 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
\ е символ за избягване, който е там, за да избегне ; се разширява от обвивката (в този случай обвивката би го интерпретирала не като част от командата за намиране, а като разделяне на две команди, които трябва да бъдат изпълнени последователно) - person 0range; 20.06.2014
comment
Просто исках да кажа: Страхотен подробен отговор, който ме подтикна да вляза, само за да мога да гласувам за вас. - person Andrioid; 15.11.2015
comment
Благодаря ви за този отговор. Как мога да използвам това, за да запазя изображението заедно с текущата му файлова структура в новата директория? - person Ryan Breece; 29.03.2018
comment
@Ryan Не виждам защо не. Просто ще трябва да създадете директориите, преди да копирате изображенията. Може или не може да има начин да се използват повече тръби, за да се интегрира това в тази едноредова команда. Но обикновено се смята, че четливостта има значение. Като следствие, силно препоръчвам вместо това да напишете bash скрипт с малко повече структура. Във всеки случай това ще бъде отделен въпрос. - person 0range; 07.12.2018
comment
Казахте, че iname е чувствителен към главни и малки букви .. но ръководството казва: -iname модел Подобно на -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  ~/

Той е проектиран от Kamil в тази публикация тук.

person HvdW    schedule 14.04.2021