Я маю папку з іменем /home/user/temps
487 папок. У кожній папці є файл під назвою thumb.png.
Я хочу скопіювати всі файли з ім'ям thumb.png в окрему папку та перейменувати їх на основі папки, з якої вони вийшли.
Я маю папку з іменем /home/user/temps
487 папок. У кожній папці є файл під назвою thumb.png.
Я хочу скопіювати всі файли з ім'ям thumb.png в окрему папку та перейменувати їх на основі папки, з якої вони вийшли.
Відповіді:
Ось вам:
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/\/thumb
?
${VARIABLE/PATTTERN/REPLACEMENT}
створює значення, VARIABLE
але з малюнком, заміненим текстом заміни. Тут викрійка /thumb
( /
потрібно уникнути, щоб вона не виглядала ${new_file//PATTERN/REPLACEMENT}
, що робить її глобальною заміною замість заміни першого появи), а текст заміни порожній.
/home/user/temps
, що не зрозуміло з питання. Якщо це не так, вам потрібно знайти або **
.
Це працює для довільно глибоких підкаталогів:
$ 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
, і замінює всі входження /
з _
.
Примітка: результат залежить від робочого каталогу та параметра шляху для пошуку. Я виконав команду з батьківського каталогу temps. Замінити cp
з echo
експериментом.
Короткий довідковий код:
#!/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
але це неминуче.
Спробуйте це
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
Редагувати
Я додав цитування, якщо будь-яке з ваших імен режисера має вбудовані символи пробілів.
Також я змінив це, щоб він тільки роздрукував команди, які потрібно виконати. Перевірте вихід сценарію, щоб переконатися, що всі файли / імена виглядають належним чином. Коли ви впевнені, що немає проблем з командами, які будуть виконуватися, видаліть echo
.
mv -i ./A A/thumb.png ../tmp/.png
- всі файли закінчуються ../tmp/.png (../tmp - мій цільовий реж).
find -type d
та побачити вихід. Це отримує всі очікувані вами каталоги? Якщо ні, то, будь ласка, додайте трохи результатів, щоб показати проблему. Щасти.
read dir
виконує розбиття слів і бере з каталогу a\nb
a і b два екземпляри, які жодне маскування не може вирішити.
Для копіювання вам потрібна команда cp , а перейменування на Linux - це те саме, що і переміщення файлу, тому вам доведеться це робити з командою mv . У Linux завжди потрібно вказати весь шлях, починаючи від джерела, якщо ви перебуваєте в іншій папці, і до папки призначення, звичайно. Я б щось подібне, для копії:
cp /source_path/file /destination_path/
або перейменувати чи перемістити
mv /source_path/old_file /destination_path/new_name_file