Заменить слово в имени каталога и в именах файлов в этом каталоге

У меня такая структура каталогов:

Bookname Edition 1 Bookname Edition 1 type1.pdf Bookname Edition 1 type2.pdf Bookname Edition 2 Bookname Edition 2 type1.pdf Bookname Edition 2 type2.pdf

Я хочу рекурсивно изменить имя из Edition в Volume каталога и имена файлов в этих каталогах.

Я начал с этого, и это нормально, если я в каталоге:

for f in *.pdf; do a="$(echo $f | sed s/Edition/Volume/)" mv "$f" "$a" done

Затем я попробовал это, чтобы изменить все файлы под каталогами, и вот тогда я застрял ...

Пожалуйста, расскажите, как это сделать или дайте мне лучший способ сделать это. В 100 каталогах имеется 15000 PDF-файлов.

7
задан 23 January 2018 в 03:04

12 ответов

Если ваша структура имеет только два уровня, вам не нужно использовать рекурсию.

Не разбирайте имена файлов с помощью sed. Если вы хотите использовать синтаксис стиля regex и sed для переименования файлов, используйте rename. Если вы используете Ubuntu 17.10, вам необходимо установить его

sudo apt install rename

. Затем вы можете использовать ответ pa4080.

С помощью rename используйте параметр -n для тестирования .

rename -n 'expression' file(s)

Вы также можете просто использовать команду mv. В качестве однострочной команды:

for d in ./*/; do mv -v "$d" "${d/Edition/Volume}"; done; for f in ./*/*; do mv -v "$f" "${f/Edition/Volume}"; done

Вы можете использовать echo для тестирования с помощью mv, то есть echo mv -v source dest, но здесь приводятся неточные результаты, если вы не проверите и не запустите циклы отдельно.

Как сценарий:

#!/bin/bash

# rename directories first
for d in ./*/; do
    mv -v "$d" "${d/Edition/Volume}"
done

# now rename files
for f in ./*/*; do
    mv -v "$f" "${f/Edition/Volume}"
done

mv и rename распознают --, чтобы указать конец опций. Поскольку в этом примере все пути начинаются с ./, нам не нужно использовать это, но если пути могут начинаться с -, используйте -- в конце опций, например rename -n -- 's/foo/bar/' *, чтобы предотвратить эти пути интерпретируются как опции.

10
ответ дан 22 May 2018 в 15:22
  • 1
    Спасибо за это - он изменил имена каталогов, но файлы под havent были переименованы. – Bishop 23 January 2018 в 16:51
  • 2
    @Bishop ну, это должно. Что именно вы сделали? – Zanna 23 January 2018 в 17:15

Если ваша структура имеет только два уровня, вам не нужно использовать рекурсию.

Не разбирайте имена файлов с помощью sed. Если вы хотите использовать синтаксис стиля regex и sed для переименования файлов, используйте rename. Если вы используете Ubuntu 17.10, вам необходимо установить его

sudo apt install rename

. Затем вы можете использовать ответ pa4080.

С помощью rename используйте параметр -n для тестирования .

rename -n 'expression' file(s)

Вы также можете просто использовать команду mv. В качестве однострочной команды:

for d in ./*/; do mv -v "$d" "${d/Edition/Volume}"; done; for f in ./*/*; do mv -v "$f" "${f/Edition/Volume}"; done

Вы можете использовать echo для тестирования с помощью mv, то есть echo mv -v source dest, но здесь приводятся неточные результаты, если вы не проверите и не запустите циклы отдельно.

Как сценарий:

#!/bin/bash # rename directories first for d in ./*/; do mv -v "$d" "${d/Edition/Volume}" done # now rename files for f in ./*/*; do mv -v "$f" "${f/Edition/Volume}" done

mv и rename распознают --, чтобы указать конец опций. Поскольку в этом примере все пути начинаются с ./, нам не нужно использовать это, но если пути могут начинаться с -, используйте -- в конце опций, например rename -n -- 's/foo/bar/' *, чтобы предотвратить эти пути интерпретируются как опции.

11
ответ дан 17 July 2018 в 22:26

Если ваша структура имеет только два уровня, вам не нужно использовать рекурсию.

Не разбирайте имена файлов с помощью sed. Если вы хотите использовать синтаксис стиля regex и sed для переименования файлов, используйте rename. Если вы используете Ubuntu 17.10, вам необходимо установить его

sudo apt install rename

. Затем вы можете использовать ответ pa4080.

С помощью rename используйте параметр -n для тестирования .

rename -n 'expression' file(s)

Вы также можете просто использовать команду mv. В качестве однострочной команды:

for d in ./*/; do mv -v "$d" "${d/Edition/Volume}"; done; for f in ./*/*; do mv -v "$f" "${f/Edition/Volume}"; done

Вы можете использовать echo для тестирования с помощью mv, то есть echo mv -v source dest, но здесь приводятся неточные результаты, если вы не проверите и не запустите циклы отдельно.

Как сценарий:

#!/bin/bash # rename directories first for d in ./*/; do mv -v "$d" "${d/Edition/Volume}" done # now rename files for f in ./*/*; do mv -v "$f" "${f/Edition/Volume}" done

mv и rename распознают --, чтобы указать конец опций. Поскольку в этом примере все пути начинаются с ./, нам не нужно использовать это, но если пути могут начинаться с -, используйте -- в конце опций, например rename -n -- 's/foo/bar/' *, чтобы предотвратить эти пути интерпретируются как опции.

11
ответ дан 23 July 2018 в 23:05

Вы можете использовать команду rename два раза для выполнения этой задачи:

rename 's/Edition/Volume/' */        # rename the directories
rename 's/Edition/Volume/' */*.pdf   # rename the PDF files inside

Вот два похожих вопроса:

Рекурсивный bash script Объяснение скрипта оболочки для рекурсивной печати полного дерева каталогов
6
ответ дан 22 May 2018 в 15:22

В многоуровневых каталогах вы можете сделать это за один шаг, но проблема в том, что вам нужно переименовать каталоги снизу вверх, чтобы команда или сценарий не изменили имя каталога до его содержимого изменяется.

В python вы можете использовать:

os.walk

в сочетании с

topdown=False

В сценарии:

#!/usr/bin/env python3
import os
import shutil
import sys

for root, dirs, files in os.walk(sys.argv[1], topdown=False):
    for f in files:
        shutil.move(
            root+"/"+f, root+"/"+f.replace("Edition", "Volume").strip()
        )
    for dr in dirs:
        shutil.move(
            root+"/"+dr, root+"/"+dr.replace("Edition", "Volume").strip()
        )
[d4 ] Сохраните сценарий как change_name.py, запустите его с каталогом как аргумент:

python3 /path/to/change_name.py <directory>

Это работает рекурсивно на любом количестве уровней.

5
ответ дан 22 May 2018 в 15:22
  • 1
    Вы можете использовать os.path.join вместо конкатенации строк с помощью "/". – Eric Duminil 23 January 2018 в 14:47
  • 2
    @EricDulusil абсолютно, но в этой ситуации (сценарий в ответе) я использовал менее подробный вариант. Нет никакой разницы в функциональности. Спасибо хоть. – Jacob Vlijm 23 January 2018 в 15:14

Используйте find с опцией -depth в сочетании с prename:

find [DIRS...] -depth | prename -n 's|Edition(?=[^/]*$)|Volume|'

Объяснение:

-depth выбирает дочерние элементы каталогов перед родителями. Инструмент, «потребляющий» выбранные имена путей для переименования, может затем переименовать детей перед родителями. s|Edition(?=[^/]*$)|Volume| заменяет первое вхождение Edition в имени пути с помощью Volume, но только если остаток не содержит /, i. е. он применяется только к последнему компоненту имени пути (достигается положительным внешним ожиданием (?=[^/]*$)). -n сообщает prename, что фактически не переименовывает пути, а печатает, как он их переименовал. Удалите эту опцию, чтобы на самом деле переименовать их.
1
ответ дан 22 May 2018 в 15:22

Используйте find с опцией -depth в сочетании с prename:

find [DIRS...] -depth | prename -n 's|Edition(?=[^/]*$)|Volume|'

Объяснение:

-depth выбирает дочерние элементы каталогов перед родителями. Инструмент, «потребляющий» выбранные имена путей для переименования, может затем переименовать детей перед родителями. s|Edition(?=[^/]*$)|Volume| заменяет первое вхождение Edition в имени пути с помощью Volume, но только если остаток не содержит /, i. е. он применяется только к последнему компоненту имени пути (достигается положительным внешним ожиданием (?=[^/]*$)). -n сообщает prename, что фактически не переименовывает пути, а печатает, как он их переименовал. Удалите эту опцию, чтобы на самом деле переименовать их.
1
ответ дан 17 July 2018 в 22:26

В многоуровневых каталогах вы можете сделать это за один шаг, но проблема в том, что вам нужно переименовать каталоги снизу вверх, чтобы команда или сценарий не изменили имя каталога до его содержимого изменяется.

В python вы можете использовать:

os.walk

в сочетании с

topdown=False

В сценарии:

#!/usr/bin/env python3 import os import shutil import sys for root, dirs, files in os.walk(sys.argv[1], topdown=False): for f in files: shutil.move( root+"/"+f, root+"/"+f.replace("Edition", "Volume").strip() ) for dr in dirs: shutil.move( root+"/"+dr, root+"/"+dr.replace("Edition", "Volume").strip() )

Сохраните сценарий как change_name.py, запустите его с каталогом как аргумент:

python3 /path/to/change_name.py <directory>

Это работает рекурсивно на любом количестве уровней.

5
ответ дан 17 July 2018 в 22:26

Вы можете использовать команду rename два раза для выполнения этой задачи:

rename 's/Edition/Volume/' */ # rename the directories rename 's/Edition/Volume/' */*.pdf # rename the PDF files inside

Вот два похожих вопроса:

Рекурсивный bash script Объяснение скрипта оболочки для рекурсивной печати полного дерева каталогов
6
ответ дан 17 July 2018 в 22:26

Используйте find с опцией -depth в сочетании с prename:

find [DIRS...] -depth | prename -n 's|Edition(?=[^/]*$)|Volume|'

Объяснение:

-depth выбирает дочерние элементы каталогов перед родителями. Инструмент, «потребляющий» выбранные имена путей для переименования, может затем переименовать детей перед родителями. s|Edition(?=[^/]*$)|Volume| заменяет первое вхождение Edition в имени пути с помощью Volume, но только если остаток не содержит /, i. е. он применяется только к последнему компоненту имени пути (достигается положительным внешним ожиданием (?=[^/]*$)). -n сообщает prename, что фактически не переименовывает пути, а печатает, как он их переименовал. Удалите эту опцию, чтобы на самом деле переименовать их.
1
ответ дан 23 July 2018 в 23:05

В многоуровневых каталогах вы можете сделать это за один шаг, но проблема в том, что вам нужно переименовать каталоги снизу вверх, чтобы команда или сценарий не изменили имя каталога до его содержимого изменяется.

В python вы можете использовать:

os.walk

в сочетании с

topdown=False

В сценарии:

#!/usr/bin/env python3 import os import shutil import sys for root, dirs, files in os.walk(sys.argv[1], topdown=False): for f in files: shutil.move( root+"/"+f, root+"/"+f.replace("Edition", "Volume").strip() ) for dr in dirs: shutil.move( root+"/"+dr, root+"/"+dr.replace("Edition", "Volume").strip() )

Сохраните сценарий как change_name.py, запустите его с каталогом как аргумент:

python3 /path/to/change_name.py <directory>

Это работает рекурсивно на любом количестве уровней.

5
ответ дан 23 July 2018 в 23:05
  • 1
    Вы можете использовать os.path.join вместо конкатенации строк с помощью "/". – Eric Duminil 23 January 2018 в 14:47
  • 2
    @EricDulusil абсолютно, но в этой ситуации (сценарий в ответе) я использовал менее подробный вариант. Нет никакой разницы в функциональности. Спасибо хоть. – Jacob Vlijm 23 January 2018 в 15:14

Вы можете использовать команду rename два раза для выполнения этой задачи:

rename 's/Edition/Volume/' */ # rename the directories rename 's/Edition/Volume/' */*.pdf # rename the PDF files inside

Вот два похожих вопроса:

Рекурсивный bash script Объяснение скрипта оболочки для рекурсивной печати полного дерева каталогов
6
ответ дан 23 July 2018 в 23:05

Другие вопросы по тегам:

Похожие вопросы: