Скопируйте большое количество файлов с новыми именами
У меня есть большое количество файлов (десятки тысяч), которые мне нужно скопировать из /dir1 в /dir2, но имя файла должно измениться как таковое:
СТАРОЕ ИМЯ ---> НОВОЕ ИМЯ
filename.txt ---> bob_filename_1253.txt
Где bob - это uid, которому принадлежит файл, а 1253 - это последний раз, когда он был изменен.
В настоящее время я добиваюсь этого с помощью сценария python, который просматривает каждый файл, а затем передает его в новое место назначения, создавая новое имя файла путем нарезки строк.
ОДНАКО, это занимает мучительно много времени. Есть ли более чистый и быстрый способ добиться этого?
Заранее спасибо!
3 ответа
Копирование
*.txt
файлы с переименованием из
dir1/
к
dir2/
каталог:
$ ls -l всего 8 drwxr-xr-x 2 пользователь пользователь 4096 лют 19 01:06 dir1 drwxr-xr-x 2 пользователь пользователь 4096 лют 19 01:08 dir2 $ ls dir1 name1.txt name2.txt name3.txt
$ для пути к файлу в./dir1/*; сделать username= $ (stat -c '%U' $filepath) && filedate= $ (stat -c '%Y' $ путь к файлу) && newpartname='dir2 /' $ n '_'"${filepath //'./ dir1 / '}" && cp $filepath "${newpartname // '. txt'}"_ $ filedate.txt; сделанный
ls dir2 / имя_пользователя1_1582067151.txt имя_пользователя2_1582067158.txt имя_пользователя3_1582067165.txt
Вы говорите, что переименование занимает много времени. Но каков размер всех ваших файлов? Вы знаете время копирования всех ваших файлов?
Следующий сценарий должен выполнить свою работу. Попробуйте, и когда результат вас устроит, удалите комментарий
#
спереди
cp -p "$oldpath""$f9" "$newpath""$new"
делать реальную работу.
Скрипт создаст в вашем домашнем каталоге файл с именем
ls_file.txt
. Этот файл необходим для хранения вывода
ls -l "$oldpath"
команда, и сценарий должен будет прочитать ее во время выполнения. После завершения сценария выполнения, то
ls_file.txt
файл больше не нужен, и вы можете его удалить.
Всегда делайте резервную копию
Чтобы создать и использовать файл сценария, выполните следующие действия:
Создайте и отредактируйте файл сценария в своем домашнем каталоге, выполнив следующую команду в терминале:
nano ~/my_script.sh
Скопируйте и вставьте следующий код в редактор, изменив
/full/path/to/old/directory/
с полным путем к вашему/dir1
каталог и/full/path/to/new/directory/
на полный путь к вашему/dir2
каталог:
#!/bin/bash
oldpath="/full/path/to/old/directory/"
newpath="/full/path/to/new/directory/"
ls -l "$oldpath" > "ls_file.txt"
while read f1 f2 f3 f4 f5 f6 f7 f8 f9
do
mod="${f6}${f7}${f8}"
mod2=$(echo "$mod" | tr -d ' :')
name="${f9%.*}"
ext="${f9##*.}"
new="$f3""_""$name""_""$mod2"".""$ext"
echo "$f9"" ---> Will be renamed ---> ""$new"
echo "----------------------------"
# cp -p "$oldpath""$f9" "$newpath""$new"
done < "ls_file.txt"
Сохраните файл сценария и выйдите из редактора, нажав Ctrl+, X затем нажмите Y.
Сделайте файл сценария исполняемым, выполнив в терминале следующую команду:
chmod +x ~/my_script.sh
Запустите сценарий, выполнив в терминале следующую команду:
bash ~/my_script.sh
Выполнено
Как это устроено?
Запуск сценария из моего домашнего каталога в тестовом каталоге
dir1/
который содержит один файл
file.txt
и тестовый каталог
dir2/
который пуст при указании
oldpath="/home/raffa/test/dir1/"
и
newpath="/home/raffa/test/dir2/"
, следующий процесс является примером того, как работает скрипт:
- Команда
ls -l /home/raffa/test/dir1/
выполняется, и вывод записывается в файл с именемls_file.txt
который затем будет содержать атрибуты и имена файлов вdir1/
в этом случае один файлfile.txt
вот так:
-rw-r--r-- 1 raffa raffa 0 Jan 25 19:49 file.txt
-rw-r--r--
это файловый режим.1
количество ссылок.- Первое
raffa
имя владельца. - Секунда
raffa
это название группы. 0
размер файла.Jan 25 19:49
(три поля) - дата и время последней модификации.file.txt
это имя файла.
. 2. Скрипт прочитает содержимое
dir1/
из
ls_file.txt
построчно и разделите каждую строку на поля (всего девять) и присвойте значение каждого поля переменной
f1 f2 f3 f4 f5 f6 f7 f8 f9
.
mod="${f6}${f7}${f8}"
назначит дату и время последнего изменения, хранящиеся в переменныхf6 f7 f8
к переменнойmod
поэтому он будет содержать такое значение:
Jan2519:49
mod2=$(echo "$mod" | tr -d ' :')
примет значение переменной$mod
удалите пробелы и двоеточия:
и присвоить его переменнойmod2
поэтому он будет содержать такое значение:
Jan251949
name="${f9%.*}"
присвоит переменной имя файла без расширенияname
поэтому он будет содержать такое значение:
file
ext="${f9##*.}"
присвоит расширение файла без имени переменнойext
поэтому он будет содержать такое значение:
txt
new="$f3""_""$name""_""$mod2"".""$ext"
отформатирует новое имя файла какowner_name_lastmodified.extension
и присвоить его переменнойnew
поэтому он будет содержать такое значение:
raffa_file_Jan251949.txt
cp -p "$oldpath""$f9" "$newpath""$new"
скопирует исходный файлfile.txt
изdir1/
кdir2/
переименовав его вraffa_file_Jan251949.txt
и попытается сохранить исходные атрибуты файла во время этого процесса, поэтому он будет выполняться следующим образом:
cp -p /home/raffa/test/dir1/file.txt /home/raffa/test/dir2/raffa_file_Jan251949.txt
Этот процесс будет повторяться для всех файлов в
dir1/
с любым расширением.
Другой формат времени:
Если вы предпочитаете, чтобы формат даты и времени последнего изменения был таким
20200125133815
где
2020
это год и
01
это месяц и
25
это день и
13
это час в 24 формате и
38
это минуты и
15
это секунды, поэтому ваши скопированные имена файлов будут выглядеть так
raffa_file_20200125133815.txt
, затем замените приведенный выше код сценария следующим кодом:
#!/bin/bash
oldpath="/full/path/to/old/directory/"
newpath="/full/path/to/new/directory/"
ls -l --time-style="+%Y%m%d%H%M%S" "$oldpath" > "ls_file.txt"
while read f1 f2 f3 f4 f5 f6 f7
do
mod="${f6}"
name="${f7%.*}"
ext="${f7##*.}"
new="$f3""_""$name""_""$mod"".""$ext"
echo "$f7"" ---> Will be renamed ---> ""$new"
echo "----------------------------"
# cp -p "$oldpath""$f7" "$newpath""$new"
done < "ls_file.txt"
Уведомление:
В некоторых случаях анализ вывода
ls
можно было бы лучше избежать.
Предполагая, что вы начинаете с пустого
dir2
чтобы вы могли копировать файлы из
dir1
к
dir2
без конфликтов, а затем переименовать их, я бы попробовал что-то вроде этого:
printf '%s\0' dir1/*.txt | xargs -r0 cp -np -t dir2/
выполнить копию, затем
cd dir2/
printf '%s\0' *.txt | xargs -r0 rename -n -- '
$_ = join "_", ( getpwuid( (stat $_)[4] ) )[0], $_, (stat $_)[9]
'
переименовать (удалить
-n
от
rename
как только вас устраивают предложенные изменения).
Хотя чаще всего он используется для простых
s/pattern/replacement/
изменения имени, основанный на Perl
rename
Команда, доступная в текущих версиях Ubuntu, может фактически переименовывать файлы на основе практически произвольных выражений Perl.
В этом случае мы можем использовать встроенный в Perl
stat
чтобы получить числовой UID и mtime, а затем используйте
getpwuid
чтобы превратить UID в имя пользователя.
(stat $_)[9]
время модификации (mtime) в секундах эпохи - если вам это нужно в другом формате, вы можете использовать
POSIX::strftime
или один из нескольких других модулей управления временем.