Как копировать и переименовывать найденные файлы в «функцию поиска» Linux?

17

У меня есть папка с именем, /home/user/tempsкоторая имеет 487 папок. В каждой папке у меня есть файл с именем thumb.png.

Я хочу скопировать все файлы с именем thumb.png в отдельную папку и переименовать их в соответствии с папкой, из которой они пришли.

Мираж
источник
переименовать их, как? Если вы замените разделитель каталога чем-то, скажем, подчеркиванием (_), вы можете столкнуться с файлами, которые уже содержат подчеркивание. Это верно для каждого действительного символа, и кроме / и \ 0, которые запрещены в именах файлов, нет безопасной гавани - любой символ может вызвать столкновение.
пользователь неизвестен
У папок есть подпапки, или просто простая, широкая структура папок?
пользователь неизвестен

Ответы:

8

Ну вот:

for file in /home/user/temps/*/thumb.png; do new_file=${file/temps/new_folder}; cp "$file" "${new_file/\/thumb/}"; done;

редактировать:

Кстати, каноническая мудрость заключается в том, что использовать findдля этого плохая идея - просто использование расширения оболочки гораздо надежнее. Кроме того, это предполагает bash, но я думаю, что это безопасное предположение :)

редактировать 2:

для ясности я разобью это

# shell-expansion to loop specified files
for file in /home/user/temps/*/thumb.png; do

    # replace 'temps' with 'new_folder' in the path
    # '/home/temps/abc/thumb.png' becomes '/home/new_folder/abc/thumb.png'
    new_file=${file/temps/new_folder};

    # drop '/thumb' from the path
    # '/home/new_folder/abc/thumb.png' becomes '/home/new_folder/abc.png'
    cp "$file" "${new_file/\/thumb/}";
done;

подробности о ${var/Pattern/Replacement}конструкции можно найти здесь .

кавычки в cpстроке важны для обработки пробелов, новых строк и т. д. в именах файлов.

Саймон
источник
new_file = new_folder? Какова цель обратной косой черты перед косой чертой new_file/\/thumb?
пользователь неизвестен
1
@user: ${VARIABLE/PATTTERN/REPLACEMENT}выдает значение VARIABLEно с заменой шаблона на текст замены. Здесь шаблон /thumb( /необходимо экранировать, чтобы он не выглядел ${new_file//PATTERN/REPLACEMENT}, что делает его глобальной заменой вместо замены первого появления), а текст замены пуст.
Жиль "ТАК - перестать быть злым"
Конечно, теперь я это вижу. :)
пользователь неизвестен
1
Вы предполагаете, что каталоги 487 находятся непосредственно под /home/user/temps, что не ясно из вопроса. Если это не так, вам нужно найти или **.
Жиль "ТАК - перестань быть злым"
@ Жиль - я действительно, вот как я читаю вопрос. Оцените суть, хотя :)
Симон
5

Это работает для сколь угодно глубоких подкаталогов:

$ find temps/ -name "thumb.png" | while IFS= read -r NAME; do cp -v "$NAME" "separate/${NAME//\//_}"; done
`temps/thumb.png' -> `separate/temps_thumb.png'
`temps/dir3/thumb.png' -> `separate/temps_dir3_thumb.png'
`temps/dir3/dir31/thumb.png' -> `separate/temps_dir3_dir31_thumb.png'
`temps/dir3/dir32/thumb.png' -> `separate/temps_dir3_dir32_thumb.png'
`temps/dir1/thumb.png' -> `separate/temps_dir1_thumb.png'
`temps/dir2/thumb.png' -> `separate/temps_dir2_thumb.png'
`temps/dir2/dir21/thumb.png' -> `separate/temps_dir2_dir21_thumb.png'

Интересная часть - расширение параметров ${NAME//\//_} . Он принимает содержание NAME, и заменяет все вхождения /с _.

Примечание: результат зависит от рабочего каталога и параметра пути для поиска. Я выполнил команду из родительского каталога временных файлов. Заменить cpс echoэкспериментом.

lesmana
источник
Сбой на файлах, которые содержат новую строку в своем имени.
пользователь неизвестен
Ну, это сработало очень хорошо. еще одна вещь, у меня также есть несколько zip-файлов в некоторых подкаталогах. Можно ли извлечь из него и морские водоросли? помните, что «zip not tar»
Mirage,
1

Краткий вспомогательный код:

#!/bin/bash
#
# echo cp "$1" ../tmp/"${1//\//_}" 
#
mv "$1" ../tmp/"${1//\//_}"

давайте назовем его «deslash.sh» и сделаем его исполняемым. Позвоните с помощью:

find -type f -name thumb.png -exec ./deslash.sh {} ";"    

Это не удастся, если столкновение существует

a/b/thumb.png # and 
a_b/thumb.png 

но это неизбежно.

Пользователь неизвестен
источник
0

Попробуй это

mkdir /home/user/thumbs
targDir=/home/user/thumbs

cd /home/user/temps

find . -type d | 
 while IFS="" read -r dir ; do
   if [[ -f "${dir}"/thumb.png ]] ; then
     echo mv -i "${dir}/thumb.png" "${targDir}/${dir}_thumb.png"
   fi
done

редактировать

Я добавил кавычки на случай, если в любом из ваших имен dir есть пробелы.

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

shellter
источник
У меня есть несколько файлов PNG в некоторых подпапках, будет ли это работать
Mirage
для моей папки "A A" он производит: mv -i ./A A/thumb.png ../tmp/.png- все файлы заканчиваются на ../tmp/.png (../tmp - это мой целевой каталог).
пользователь неизвестен
Добавьте кавычки и фигурные скобки вокруг всех переменных в приведенном выше коде, то есть "$ {dir}"
shellter
@ Mirror51 писал: «файлы в некоторых подпапках, это будет работать». Да, это должно. Знаете ли вы, что вы можете выполнить каждый шаг этого скрипта отдельно (или при соединении каждого набора каналов). Вы можете выполнить только find -type dи увидеть результат. Это получает все каталоги, которые вы ожидаете? Если нет, пожалуйста, добавьте вывод, чтобы показать проблему. Удачи.
shellter
Не сработает read dirвыполняет разбиение слов и извлекает из каталогов a\nba и b как два экземпляра, которые не может решить ни одна маскировка.
пользователь неизвестен
-1

Для копирования вам нужна команда cp , а переименование для linux - это то же самое, что и перемещение файла, поэтому вы должны сделать это с помощью команды mv . В Linux вы всегда должны указывать весь путь, от источника, если вы находитесь в другой папке, и, конечно, до папки назначения. Я бы что-то вроде этого, для копирования:

cp /source_path/file /destination_path/

или переименовать или переместить

mv /source_path/old_file /destination_path/new_name_file

источник
Это только малая часть вопроса автора. Теперь объясните, как перебирать каталоги и копировать миниатюры :-)
ОП хочет использоватьfind
Да, вы правы ... Я не знаю, что со мной случилось ...