переименовать файлы в Linux согласно заданным именам в txt-файле используя скрипт
В папке /home/user/Downloads/videos/
расположены скачанные файлы, и из-за того что имена файлов именуются как 000.mp4
при их скачивании, система дописывает нумерацию перед расширением файла - 000.556.mp4
.
Также имеется исходная нумерация файла полученная из ссылки на файл на сервере, и информация на уже переименованный файл в файловой системе у меня на ПК, хранится в файле /home/user/Downloads/downloads.txt
downloads.txt
внутри, здесь представлена информация только о 3 файлах:
Name: 000.557.mp4
Folder: /home/user/Downloads/videos
URI: http://example.com/videos/2004/000.mp4
Message: Resumable
Name: 000.556.mp4
Folder: /home/user/Downloads/videos
URI: http://example.com/videos/1979/000.mp4
Message: Resumable
Name: 000.555.mp4
Folder: /home/user/Downloads/videos
URI: http://example.com/videos/1977/000.mp4
Message: Resumable
где:
исходное название:
URI: http://example.com/videos/2004/000.mp4
переименованное у меня в системе:
Name: 000.557.mp4
Нужно запустить скрипт с командной строки, который прочитает информацию с файла downloads.txt
и переименует все файлы в папке ...videos/
в исходную нумерацию (как файлы хранятся на сервере).
000.557.mp4 ===> 2004.mp4
000.556.mp4 ===> 1979.mp4
000.555.mp4 ===> 1977.mp4
то есть нужно использовать нумерацию, из исходной ссылки, которая указана после example.com/videos/
и перед /000.mp4
Подскажите, пожалуйста, как будет выглядеть такой скрипт, чтобы он смог обработать файлы из папки проставив соответствующую нумерацию для каждого файла, понимая что информация на каждый файл разделена переходом на новую строку!?
Ответы (2 шт):
Примерно вот так, без обработки всяких исключительных ситуаций.
import re
import pathlib
vdir = pathlib.Path("/home/user/Downloads/videos/")
with open("/home/user/Downloads/downloads.txt") as f:
for l in f:
for fname in re.findall("Name: (000.\d+.mp4)", l):
while True:
url = re.findall("URI: http://example.com/videos/(\d+)/000(.mp4)", next(f))
if url:
break
try:
(vdir / fname).rename(vdir / ''.join(*url))
except FileNotFoundError:
print(f'{fname} not found')
Структурированный файл хорошо парсится awk
. Для вашего случая подходит вот такая программа:
/Name:/ { name = $2 } # берет имя файла из второго слова в строке, содержащей 'Name:'
/URI:/ { # обрабатывает строку, содержащую 'URI:'
# извлекает /1977/ и сохраняет в массив arr
# arr[0] содержит /1977/, arr[1] - 1977
match($2, /\/([0-9]+)\//, arr);
printf "mv %s %s.mp4;\n", name, arr[1];
}
На выходе генерирует скрипт для шелла
mv 000.557.mp4 2004.mp4;
mv 000.556.mp4 1979.mp4;
mv 000.555.mp4 1977.mp4;
Можно вытянуть в одну строку:
gawk -e '/Name:/{name=$2};/URI:/{ match($2,/\/([0-9]+)\//, arr); printf "mv %s %s.mp4;\n",name,arr[1]}' some.txt | /bin/sh -s
UPDATE
скрипт rename.sh
#!/bin/bash
txt_file=$1
if [ -z "$txt_file" ]; then
echo "$0 TEXT_FILE" > /dev/stderr
exit 1
fi
function mk_script {
gawk \
-e '/Name:/{name=$2};/URI:/{ match($2,/\/([0-9]+)\//, arr); printf "mv -- \"%s\" \"%s.mp4\";\n",name,arr[1]}' \
$txt_file
}
mk_script $1 | sh -s
Этот скрипт вызывается так rename.sh <text-file>
Небольшое изменение в AWK: теперь имена файлов при переименовании оборачиваются в кавычки и после mv добавлена опция --
, которая означает, что после этого места знак -
не будет интепретироваться как опции.