, это уникальная ситуация, которую лучше объяснить с помощью примера
Пример 1, скажем, у меня есть папка с именем A, B.mkv и C.srt - это два файла в папке, я хочу переименовать эти файлы в A.mkv и A.srt.
практично Например, папка с именами American Sniper (2014) и American.Sniper.2014.1080p.BluRay.x264.YIFY.mkv и American.Sniper.2014.Subtitle.BluRay.ShaAnig.srt - это два файла в папке, вы хотите переименовать эти файлы в American Sniper (2014).mkv и American Sniper (2014).srt
Пример 2
Это должно быть рекурсивным, скажем, у меня есть папка с именем A, B и C - две подпапки в папке A. содержимое B и C выглядит следующим образом
Должно быть преобразовано в
Даже когда я запускать алгоритм / скрипт / команду в папке A
Третья вещь, которую он должен делать, это Игнорировать скрытые файлы
example
[!d13]
должно привести к
Наконец, он должен работать с несколькими папками в время
Существует несколько способов подхода к этому вопросу. Пожалуйста, внимательно прочитайте инструкции для получения наилучших результатов.
В этом ответе:
Подход Python find + bash подход только для bash-подхода с globstar [ ! d6]Python - довольно мощный язык для системного администрирования, а перемещение дерева каталогов может быть выполнено с помощью функции os.walk(). В приведенном ниже скрипте мы делаем именно это: мы находим все файлы и работаем над каждым из них, определяя полный путь к каждому файлу, расширение файла и переименование его с помощью функции os.rename().
#!/usr/bin/env python3
import os,sys
def get_all_files(treeroot):
for dir,subdirs,files in os.walk(treeroot):
for f in files:
if f in __file__: continue
fullpath = os.path.realpath( os.path.join(dir,f) )
extension = fullpath.split('.')[-1]
newpath = os.path.join(dir, dir + '.' + extension)
print('Move ' + fullpath + ' to ' + newpath )
# os.rename(fullpath,newpath)
def main():
top_dir="."
# If directory not given, assume cwd
if len(sys.argv) == 2: top_dir=sys.argv[1]
get_all_files(top_dir)
if __name__ == '__main__' : main()
ПРИМЕЧАНИЕ. Очень важно, чтобы на самом деле переименовать файлы, которые нужно удалить # перед # os.rename(fullpath,newpath).
Применяются все стандартные правила для сценариев: - сохранить его как add_location_name.py в самой верхней папке - сделать исполняемый файл с chmod +x ./add_location_name.py - запустить с [ f18]
Вот пример того, как это работает на практике. Я создал каталог с двумя другими, Movie A (2016) и Movie B (2016). Внутри они оба имеют два файла. Наш скрипт живет в том же каталоге:
$ tree
.
├── add_location_name.py
├── Movie A (2014)
│ ├── filea.mkv
│ └── fileb.srt
└── Movie B (2016)
├── filea.mkv
└── fileb.srt
Поэтому, когда мы запускаем скрипт, мы увидим следующий вывод:
$ ./add_location_name.py
Move /home/xieerqi/testdir/Movie A (2014)/fileb.srt to ./Movie A (2014)/./Movie A (2014).srt
Move /home/xieerqi/testdir/Movie A (2014)/filea.mkv to ./Movie A (2014)/./Movie A (2014).mkv
Move /home/xieerqi/testdir/Movie B (2016)/fileb.srt to ./Movie B (2016)/./Movie B (2016).srt
Move /home/xieerqi/testdir/Movie B (2016)/filea.mkv to ./Movie B (2016)/./Movie B (2016).mkv
find полезно во многих отношениях, особенно при выполнении операций на нескольких уровнях дерева каталогов. В этом конкретном случае мы можем использовать его для фильтрации всех файлов и выполнить операцию переименования.
Прежде всего позвольте мне дать вам решение:
find -type f -exec bash -c 'fp=$(dirname "$1");fn=$(basename "$fp");px="${1##*.}";mv "$1" "$fp"/"$fn"."$px"' sh "{}" \;
[d21 ] Выглядит долго и страшно, не так ли? Прежде всего вам нужно признать, что происходит две вещи: команда find находит все файлы, а часть bash - это то, что на самом деле выполняет переименование. С внешней стороны мы видим простую команду:
find -type f -exec <COMMAND> \;
Это находит только все файлы (без каталогов или символических ссылок) и вызывает некоторую другую команду всякий раз, когда находит файл. В этом случае у нас есть специальная КОМАНДА bash.
Итак, что делает bash -c 'fp=$(dirname "$1");fn=$(basename "$fp");px="${1##*.}";mv "$1" "$fp"/"$fn"."$px"' sh "{}" часть? Ну, прежде всего, узнайте структуру: bash -c 'command1;command2' arg0 arg1. Всякий раз, когда используется флаг -c, первый аргумент командной строки arg0 будет установлен как $0, имя оболочки, поэтому оно не имеет значения, но важно "{}". Это цитируемый placeholder для имени файла, который find будет передан как аргумент bash.
Внутри команды bash мы извлекаем путь к файлу fp=$(dirname "$1"), имя каталога fn=$(basename "$fp"), и расширение файла или префикс px="${1##*.}". Все это отлично работает, так как мы запускаем команду из самого верхнего каталога (очень важно!). Наконец, mv "$1" "$fp"/"$fn"."$px"' sh "{}" переименует исходный файл, который find дал нам новое имя файла, которое мы создали с помощью "$fp"/"$fn"."$px", используя все эти переменные.
Тест команды выполняется в том же каталоге, что и раньше:
$ tree
.
├── Movie A (2014)
│ ├── filea.mkv
│ └── fileb.srt
└── Movie B (2016)
├── filea.mkv
└── fileb.srt
2 directories, 4 files
И если мы запустим команду, то с echo вместо mv мы увидим, что каждое имя файла переименовывается соответственно.
$ find -type f -exec bash -c 'fp=$(dirname "$1");fn=$(basename "$fp");px="${1##*.}";echo "$1" "$fp"/"$fn"."$px"' sh ">
./Movie A (2014)/fileb.srt ./Movie A (2014)/Movie A (2014).srt
./Movie A (2014)/filea.mkv ./Movie A (2014)/Movie A (2014).mkv
./Movie B (2016)/fileb.srt ./Movie B (2016)/Movie B (2016).srt
./Movie B (2016)/filea.mkv ./Movie B (2016)/Movie B (2016).mkv
ПРИМЕЧАНИЕ: : приведенная выше команда использует echo только для тестирования. Когда вы используете mv, выход отсутствует, поэтому команда отключена.
Вышеупомянутые два подхода используйте рекурсивный обход дерева. Поскольку в вашем примере у вас есть только два уровня в дереве каталогов (каталог и файлы фильмов), мы можем упростить нашу предыдущую команду оболочки следующим образом:
for f in */* ;do fp=$(dirname "$f"); ext="${f##*.}" ; echo "$f" "$fp"/"$fp"."$ext" ;done
Опять же, ту же идею - замените echo на [ f44], когда вы уверены, что он работает правильно.
Результаты испытаний одинаковы:
$ tree
.
├── add_location_name.py
├── Movie A (2014)
│ ├── filea.mkv
│ └── fileb.srt
└── Movie B (2016)
├── filea.mkv
└── fileb.srt
2 directories, 5 files
$ for f in */* ;do fp=$(dirname "$f"); ext="${f##*.}" ; echo "$f" "$fp"/"$fp"."$ext" ;done
Movie A (2014)/filea.mkv Movie A (2014)/Movie A (2014).mkv
Movie A (2014)/fileb.srt Movie A (2014)/Movie A (2014).srt
Movie B (2016)/filea.mkv Movie B (2016)/Movie B (2016).mkv
Movie B (2016)/fileb.srt Movie B (2016)/Movie B (2016).srt
Существует несколько способов подхода к этому вопросу. Пожалуйста, внимательно прочитайте инструкции для получения наилучших результатов.
В этом ответе:
Подход Python find + bash подход только для bash-подхода с globstar [ ! d6]Python - довольно мощный язык для системного администрирования, а перемещение дерева каталогов может быть выполнено с помощью функции os.walk(). В приведенном ниже скрипте мы делаем именно это: мы находим все файлы и работаем над каждым из них, определяя полный путь к каждому файлу, расширение файла и переименование его с помощью функции os.rename().
#!/usr/bin/env python3
import os,sys
def get_all_files(treeroot):
for dir,subdirs,files in os.walk(treeroot):
for f in files:
if f in __file__: continue
fullpath = os.path.realpath( os.path.join(dir,f) )
extension = fullpath.split('.')[-1]
newpath = os.path.join(dir, dir + '.' + extension)
print('Move ' + fullpath + ' to ' + newpath )
# os.rename(fullpath,newpath)
def main():
top_dir="."
# If directory not given, assume cwd
if len(sys.argv) == 2: top_dir=sys.argv[1]
get_all_files(top_dir)
if __name__ == '__main__' : main()
ПРИМЕЧАНИЕ. Очень важно, чтобы на самом деле переименовать файлы, которые нужно удалить # перед # os.rename(fullpath,newpath).
Применяются все стандартные правила для сценариев: - сохранить его как add_location_name.py в самой верхней папке - сделать исполняемый файл с chmod +x ./add_location_name.py - запустить с ./add_location_name.py
Вот пример того, как это работает на практике. Я создал каталог с двумя другими, Movie A (2016) и Movie B (2016). Внутри они оба имеют два файла. Наш скрипт живет в том же каталоге:
$ tree
.
├── add_location_name.py
├── Movie A (2014)
│ ├── filea.mkv
│ └── fileb.srt
└── Movie B (2016)
├── filea.mkv
└── fileb.srt
Поэтому, когда мы запускаем скрипт, мы увидим следующий вывод:
$ ./add_location_name.py
Move /home/xieerqi/testdir/Movie A (2014)/fileb.srt to ./Movie A (2014)/./Movie A (2014).srt
Move /home/xieerqi/testdir/Movie A (2014)/filea.mkv to ./Movie A (2014)/./Movie A (2014).mkv
Move /home/xieerqi/testdir/Movie B (2016)/fileb.srt to ./Movie B (2016)/./Movie B (2016).srt
Move /home/xieerqi/testdir/Movie B (2016)/filea.mkv to ./Movie B (2016)/./Movie B (2016).mkv
find полезно во многих отношениях, особенно при выполнении операций на нескольких уровнях дерева каталогов. В этом конкретном случае мы можем использовать его для фильтрации всех файлов и выполнить операцию переименования.
Прежде всего позвольте мне дать вам решение:
find -type f -exec bash -c 'fp=$(dirname "$1");fn=$(basename "$fp");px="${1##*.}";mv "$1" "$fp"/"$fn"."$px"' sh "{}" \;
Выглядит долго и страшно, не так ли?
Прежде всего вам нужно признать, что происходит две вещи: команда find находит все файлы, а часть bash - это то, что на самом деле выполняет переименование. С внешней стороны мы видим простую команду:
find -type f -exec <COMMAND> \;
Это находит только все файлы (без каталогов или символических ссылок) и вызывает некоторую другую команду всякий раз, когда находит файл. В этом случае у нас есть специальная КОМАНДА bash.
Итак, что делает bash -c 'fp=$(dirname "$1");fn=$(basename "$fp");px="${1##*.}";mv "$1" "$fp"/"$fn"."$px"' sh "{}" часть? Ну, прежде всего, узнайте структуру: bash -c 'command1;command2' arg0 arg1. Всякий раз, когда используется флаг -c, первый аргумент командной строки arg0 будет установлен как $0, имя оболочки, поэтому оно не имеет значения, но важно "{}". Это цитируемый placeholder для имени файла, который find будет передан как аргумент bash.
Внутри команды bash мы извлекаем путь к файлу fp=$(dirname "$1"), имя каталога fn=$(basename "$fp"), и расширение файла или префикс px="${1##*.}". Все это отлично работает, так как мы запускаем команду из самого верхнего каталога (очень важно!). Наконец, mv "$1" "$fp"/"$fn"."$px"' sh "{}" переименует исходный файл, который find дал нам новое имя файла, которое мы создали с помощью "$fp"/"$fn"."$px", используя все эти переменные.
Тест команды выполняется в том же каталоге, что и раньше:
$ tree
.
├── Movie A (2014)
│ ├── filea.mkv
│ └── fileb.srt
└── Movie B (2016)
├── filea.mkv
└── fileb.srt
2 directories, 4 files
И если мы запустим команду, то с echo вместо mv мы увидим, что каждое имя файла переименовывается соответственно.
$ find -type f -exec bash -c 'fp=$(dirname "$1");fn=$(basename "$fp");px="${1##*.}";echo "$1" "$fp"/"$fn"."$px"' sh ">
./Movie A (2014)/fileb.srt ./Movie A (2014)/Movie A (2014).srt
./Movie A (2014)/filea.mkv ./Movie A (2014)/Movie A (2014).mkv
./Movie B (2016)/fileb.srt ./Movie B (2016)/Movie B (2016).srt
./Movie B (2016)/filea.mkv ./Movie B (2016)/Movie B (2016).mkv
ПРИМЕЧАНИЕ: : приведенная выше команда использует echo только для тестирования. Когда вы используете mv, выход отсутствует, поэтому команда отключена.
Вышеупомянутые два подхода используйте рекурсивный обход дерева. Поскольку в вашем примере у вас есть только два уровня в дереве каталогов (каталог и файлы фильмов), мы можем упростить нашу предыдущую команду оболочки следующим образом:
for f in */* ;do fp=$(dirname "$f"); ext="${f##*.}" ; echo "$f" "$fp"/"$fp"."$ext" ;done
Опять же, ту же идею - замените echo на mv, когда вы уверены, что он работает правильно.
Результаты испытаний одинаковы:
$ tree
.
├── add_location_name.py
├── Movie A (2014)
│ ├── filea.mkv
│ └── fileb.srt
└── Movie B (2016)
├── filea.mkv
└── fileb.srt
2 directories, 5 files
$ for f in */* ;do fp=$(dirname "$f"); ext="${f##*.}" ; echo "$f" "$fp"/"$fp"."$ext" ;done
Movie A (2014)/filea.mkv Movie A (2014)/Movie A (2014).mkv
Movie A (2014)/fileb.srt Movie A (2014)/Movie A (2014).srt
Movie B (2016)/filea.mkv Movie B (2016)/Movie B (2016).mkv
Movie B (2016)/fileb.srt Movie B (2016)/Movie B (2016).srt
Существует несколько способов подхода к этому вопросу. Пожалуйста, внимательно прочитайте инструкции для получения наилучших результатов.
В этом ответе:
Подход Python find + bash подход только для bash-подхода с globstar [ ! d6]Python - довольно мощный язык для системного администрирования, а перемещение дерева каталогов может быть выполнено с помощью функции os.walk(). В приведенном ниже скрипте мы делаем именно это: мы находим все файлы и работаем над каждым из них, определяя полный путь к каждому файлу, расширение файла и переименование его с помощью функции os.rename().
#!/usr/bin/env python3
import os,sys
def get_all_files(treeroot):
for dir,subdirs,files in os.walk(treeroot):
for f in files:
if f in __file__: continue
fullpath = os.path.realpath( os.path.join(dir,f) )
extension = fullpath.split('.')[-1]
newpath = os.path.join(dir, dir + '.' + extension)
print('Move ' + fullpath + ' to ' + newpath )
# os.rename(fullpath,newpath)
def main():
top_dir="."
# If directory not given, assume cwd
if len(sys.argv) == 2: top_dir=sys.argv[1]
get_all_files(top_dir)
if __name__ == '__main__' : main()
ПРИМЕЧАНИЕ. Очень важно, чтобы на самом деле переименовать файлы, которые нужно удалить # перед # os.rename(fullpath,newpath).
Применяются все стандартные правила для сценариев: - сохранить его как add_location_name.py в самой верхней папке - сделать исполняемый файл с chmod +x ./add_location_name.py - запустить с ./add_location_name.py
Вот пример того, как это работает на практике. Я создал каталог с двумя другими, Movie A (2016) и Movie B (2016). Внутри они оба имеют два файла. Наш скрипт живет в том же каталоге:
$ tree
.
├── add_location_name.py
├── Movie A (2014)
│ ├── filea.mkv
│ └── fileb.srt
└── Movie B (2016)
├── filea.mkv
└── fileb.srt
Поэтому, когда мы запускаем скрипт, мы увидим следующий вывод:
$ ./add_location_name.py
Move /home/xieerqi/testdir/Movie A (2014)/fileb.srt to ./Movie A (2014)/./Movie A (2014).srt
Move /home/xieerqi/testdir/Movie A (2014)/filea.mkv to ./Movie A (2014)/./Movie A (2014).mkv
Move /home/xieerqi/testdir/Movie B (2016)/fileb.srt to ./Movie B (2016)/./Movie B (2016).srt
Move /home/xieerqi/testdir/Movie B (2016)/filea.mkv to ./Movie B (2016)/./Movie B (2016).mkv
find полезно во многих отношениях, особенно при выполнении операций на нескольких уровнях дерева каталогов. В этом конкретном случае мы можем использовать его для фильтрации всех файлов и выполнить операцию переименования.
Прежде всего позвольте мне дать вам решение:
find -type f -exec bash -c 'fp=$(dirname "$1");fn=$(basename "$fp");px="${1##*.}";mv "$1" "$fp"/"$fn"."$px"' sh "{}" \;
Выглядит долго и страшно, не так ли?
Прежде всего вам нужно признать, что происходит две вещи: команда find находит все файлы, а часть bash - это то, что на самом деле выполняет переименование. С внешней стороны мы видим простую команду:
find -type f -exec <COMMAND> \;
Это находит только все файлы (без каталогов или символических ссылок) и вызывает некоторую другую команду всякий раз, когда находит файл. В этом случае у нас есть специальная КОМАНДА bash.
Итак, что делает bash -c 'fp=$(dirname "$1");fn=$(basename "$fp");px="${1##*.}";mv "$1" "$fp"/"$fn"."$px"' sh "{}" часть? Ну, прежде всего, узнайте структуру: bash -c 'command1;command2' arg0 arg1. Всякий раз, когда используется флаг -c, первый аргумент командной строки arg0 будет установлен как $0, имя оболочки, поэтому оно не имеет значения, но важно "{}". Это цитируемый placeholder для имени файла, который find будет передан как аргумент bash.
Внутри команды bash мы извлекаем путь к файлу fp=$(dirname "$1"), имя каталога fn=$(basename "$fp"), и расширение файла или префикс px="${1##*.}". Все это отлично работает, так как мы запускаем команду из самого верхнего каталога (очень важно!). Наконец, mv "$1" "$fp"/"$fn"."$px"' sh "{}" переименует исходный файл, который find дал нам новое имя файла, которое мы создали с помощью "$fp"/"$fn"."$px", используя все эти переменные.
Тест команды выполняется в том же каталоге, что и раньше:
$ tree
.
├── Movie A (2014)
│ ├── filea.mkv
│ └── fileb.srt
└── Movie B (2016)
├── filea.mkv
└── fileb.srt
2 directories, 4 files
И если мы запустим команду, то с echo вместо mv мы увидим, что каждое имя файла переименовывается соответственно.
$ find -type f -exec bash -c 'fp=$(dirname "$1");fn=$(basename "$fp");px="${1##*.}";echo "$1" "$fp"/"$fn"."$px"' sh ">
./Movie A (2014)/fileb.srt ./Movie A (2014)/Movie A (2014).srt
./Movie A (2014)/filea.mkv ./Movie A (2014)/Movie A (2014).mkv
./Movie B (2016)/fileb.srt ./Movie B (2016)/Movie B (2016).srt
./Movie B (2016)/filea.mkv ./Movie B (2016)/Movie B (2016).mkv
ПРИМЕЧАНИЕ: : приведенная выше команда использует echo только для тестирования. Когда вы используете mv, выход отсутствует, поэтому команда отключена.
Вышеупомянутые два подхода используйте рекурсивный обход дерева. Поскольку в вашем примере у вас есть только два уровня в дереве каталогов (каталог и файлы фильмов), мы можем упростить нашу предыдущую команду оболочки следующим образом:
for f in */* ;do fp=$(dirname "$f"); ext="${f##*.}" ; echo "$f" "$fp"/"$fp"."$ext" ;done
Опять же, ту же идею - замените echo на mv, когда вы уверены, что он работает правильно.
Результаты испытаний одинаковы:
$ tree
.
├── add_location_name.py
├── Movie A (2014)
│ ├── filea.mkv
│ └── fileb.srt
└── Movie B (2016)
├── filea.mkv
└── fileb.srt
2 directories, 5 files
$ for f in */* ;do fp=$(dirname "$f"); ext="${f##*.}" ; echo "$f" "$fp"/"$fp"."$ext" ;done
Movie A (2014)/filea.mkv Movie A (2014)/Movie A (2014).mkv
Movie A (2014)/fileb.srt Movie A (2014)/Movie A (2014).srt
Movie B (2016)/filea.mkv Movie B (2016)/Movie B (2016).mkv
Movie B (2016)/fileb.srt Movie B (2016)/Movie B (2016).srt
Существует несколько способов подхода к этому вопросу. Пожалуйста, внимательно прочитайте инструкции для получения наилучших результатов.
В этом ответе:
Подход Python find + bash подход только для bash-подхода с globstar [ ! d6]Python - довольно мощный язык для системного администрирования, а перемещение дерева каталогов может быть выполнено с помощью функции os.walk(). В приведенном ниже скрипте мы делаем именно это: мы находим все файлы и работаем над каждым из них, определяя полный путь к каждому файлу, расширение файла и переименование его с помощью функции os.rename().
#!/usr/bin/env python3
import os,sys
def get_all_files(treeroot):
for dir,subdirs,files in os.walk(treeroot):
for f in files:
if f in __file__: continue
fullpath = os.path.realpath( os.path.join(dir,f) )
extension = fullpath.split('.')[-1]
newpath = os.path.join(dir, dir + '.' + extension)
print('Move ' + fullpath + ' to ' + newpath )
# os.rename(fullpath,newpath)
def main():
top_dir="."
# If directory not given, assume cwd
if len(sys.argv) == 2: top_dir=sys.argv[1]
get_all_files(top_dir)
if __name__ == '__main__' : main()
ПРИМЕЧАНИЕ. Очень важно, чтобы на самом деле переименовать файлы, которые нужно удалить # перед # os.rename(fullpath,newpath).
Применяются все стандартные правила для сценариев: - сохранить его как add_location_name.py в самой верхней папке - сделать исполняемый файл с chmod +x ./add_location_name.py - запустить с ./add_location_name.py
Вот пример того, как это работает на практике. Я создал каталог с двумя другими, Movie A (2016) и Movie B (2016). Внутри они оба имеют два файла. Наш скрипт живет в том же каталоге:
$ tree
.
├── add_location_name.py
├── Movie A (2014)
│ ├── filea.mkv
│ └── fileb.srt
└── Movie B (2016)
├── filea.mkv
└── fileb.srt
Поэтому, когда мы запускаем скрипт, мы увидим следующий вывод:
$ ./add_location_name.py
Move /home/xieerqi/testdir/Movie A (2014)/fileb.srt to ./Movie A (2014)/./Movie A (2014).srt
Move /home/xieerqi/testdir/Movie A (2014)/filea.mkv to ./Movie A (2014)/./Movie A (2014).mkv
Move /home/xieerqi/testdir/Movie B (2016)/fileb.srt to ./Movie B (2016)/./Movie B (2016).srt
Move /home/xieerqi/testdir/Movie B (2016)/filea.mkv to ./Movie B (2016)/./Movie B (2016).mkv
find полезно во многих отношениях, особенно при выполнении операций на нескольких уровнях дерева каталогов. В этом конкретном случае мы можем использовать его для фильтрации всех файлов и выполнить операцию переименования.
Прежде всего позвольте мне дать вам решение:
find -type f -exec bash -c 'fp=$(dirname "$1");fn=$(basename "$fp");px="${1##*.}";mv "$1" "$fp"/"$fn"."$px"' sh "{}" \;
Выглядит долго и страшно, не так ли?
Прежде всего вам нужно признать, что происходит две вещи: команда find находит все файлы, а часть bash - это то, что на самом деле выполняет переименование. С внешней стороны мы видим простую команду:
find -type f -exec <COMMAND> \;
Это находит только все файлы (без каталогов или символических ссылок) и вызывает некоторую другую команду всякий раз, когда находит файл. В этом случае у нас есть специальная КОМАНДА bash.
Итак, что делает bash -c 'fp=$(dirname "$1");fn=$(basename "$fp");px="${1##*.}";mv "$1" "$fp"/"$fn"."$px"' sh "{}" часть? Ну, прежде всего, узнайте структуру: bash -c 'command1;command2' arg0 arg1. Всякий раз, когда используется флаг -c, первый аргумент командной строки arg0 будет установлен как $0, имя оболочки, поэтому оно не имеет значения, но важно "{}". Это цитируемый placeholder для имени файла, который find будет передан как аргумент bash.
Внутри команды bash мы извлекаем путь к файлу fp=$(dirname "$1"), имя каталога fn=$(basename "$fp"), и расширение файла или префикс px="${1##*.}". Все это отлично работает, так как мы запускаем команду из самого верхнего каталога (очень важно!). Наконец, mv "$1" "$fp"/"$fn"."$px"' sh "{}" переименует исходный файл, который find дал нам новое имя файла, которое мы создали с помощью "$fp"/"$fn"."$px", используя все эти переменные.
Тест команды выполняется в том же каталоге, что и раньше:
$ tree
.
├── Movie A (2014)
│ ├── filea.mkv
│ └── fileb.srt
└── Movie B (2016)
├── filea.mkv
└── fileb.srt
2 directories, 4 files
И если мы запустим команду, то с echo вместо mv мы увидим, что каждое имя файла переименовывается соответственно.
$ find -type f -exec bash -c 'fp=$(dirname "$1");fn=$(basename "$fp");px="${1##*.}";echo "$1" "$fp"/"$fn"."$px"' sh ">
./Movie A (2014)/fileb.srt ./Movie A (2014)/Movie A (2014).srt
./Movie A (2014)/filea.mkv ./Movie A (2014)/Movie A (2014).mkv
./Movie B (2016)/fileb.srt ./Movie B (2016)/Movie B (2016).srt
./Movie B (2016)/filea.mkv ./Movie B (2016)/Movie B (2016).mkv
ПРИМЕЧАНИЕ: : приведенная выше команда использует echo только для тестирования. Когда вы используете mv, выход отсутствует, поэтому команда отключена.
Вышеупомянутые два подхода используйте рекурсивный обход дерева. Поскольку в вашем примере у вас есть только два уровня в дереве каталогов (каталог и файлы фильмов), мы можем упростить нашу предыдущую команду оболочки следующим образом:
for f in */* ;do fp=$(dirname "$f"); ext="${f##*.}" ; echo "$f" "$fp"/"$fp"."$ext" ;done
Опять же, ту же идею - замените echo на mv, когда вы уверены, что он работает правильно.
Результаты испытаний одинаковы:
$ tree
.
├── add_location_name.py
├── Movie A (2014)
│ ├── filea.mkv
│ └── fileb.srt
└── Movie B (2016)
├── filea.mkv
└── fileb.srt
2 directories, 5 files
$ for f in */* ;do fp=$(dirname "$f"); ext="${f##*.}" ; echo "$f" "$fp"/"$fp"."$ext" ;done
Movie A (2014)/filea.mkv Movie A (2014)/Movie A (2014).mkv
Movie A (2014)/fileb.srt Movie A (2014)/Movie A (2014).srt
Movie B (2016)/filea.mkv Movie B (2016)/Movie B (2016).mkv
Movie B (2016)/fileb.srt Movie B (2016)/Movie B (2016).srt
Существует несколько способов подхода к этому вопросу. Пожалуйста, внимательно прочитайте инструкции для получения наилучших результатов.
В этом ответе:
find
+ bash
подход Python - довольно мощный язык для системного администрирования, а перемещение дерева каталогов можно выполнить с помощью функции os.walk()
. В приведенном ниже скрипте мы делаем именно это: мы находим все файлы и работаем над каждым из них, определяя полный путь к каждому файлу, расширение файла и переименование его с помощью функции os.rename()
.
#!/usr/bin/env python3
import os,sys
def get_all_files(treeroot):
for dir,subdirs,files in os.walk(treeroot):
for f in files:
if f in __file__: continue
fullpath = os.path.realpath( os.path.join(dir,f) )
extension = fullpath.split('.')[-1]
newpath = os.path.join(dir, dir + '.' + extension)
print('Move ' + fullpath + ' to ' + newpath )
# os.rename(fullpath,newpath)
def main():
top_dir="."
# If directory not given, assume cwd
if len(sys.argv) == 2: top_dir=sys.argv[1]
get_all_files(top_dir)
if __name__ == '__main__' : main()
ПРИМЕЧАНИЕ. Очень важно, чтобы на самом деле переименовать файлы, которые необходимо удалить #
перед # os.rename(fullpath,newpath)
.
Используются все стандартные правила для сценариев: - сохранить его как add_location_name.py
в самом верхнем каталоге - сделать исполняемый файл с chmod +x ./add_location_name.py
- запустить с ./add_location_name.py
Вот пример того, как это работает на практике. Я создал каталог с двумя другими, Movie A (2016)
и Movie B (2016)
. Внутри они оба имеют два файла. Наш скрипт живет в том же каталоге:
$ tree
.
├── add_location_name.py
├── Movie A (2014)
│ ├── filea.mkv
│ └── fileb.srt
└── Movie B (2016)
├── filea.mkv
└── fileb.srt
Поэтому, когда мы запускаем скрипт, мы увидим следующий вывод:
$ ./add_location_name.py
Move /home/xieerqi/testdir/Movie A (2014)/fileb.srt to ./Movie A (2014)/./Movie A (2014).srt
Move /home/xieerqi/testdir/Movie A (2014)/filea.mkv to ./Movie A (2014)/./Movie A (2014).mkv
Move /home/xieerqi/testdir/Movie B (2016)/fileb.srt to ./Movie B (2016)/./Movie B (2016).srt
Move /home/xieerqi/testdir/Movie B (2016)/filea.mkv to ./Movie B (2016)/./Movie B (2016).mkv
find
полезно во многих отношениях, особенно при выполнении операций на нескольких уровнях дерева каталогов. В этом конкретном случае мы можем использовать его для фильтрации всех файлов и выполнить операцию переименования.
Прежде всего позвольте мне дать вам решение:
find -type f -exec bash -c 'fp=$(dirname "$1");fn=$(basename "$fp");px="${1##*.}";mv "$1" "$fp"/"$fn"."$px"' sh "{}" \;
Выглядит долго и страшно, не так ли? Но не беспокойтесь, давайте рассмотрим, как это работает.
Прежде всего вам нужно признать, что происходит две вещи: команда find
находит все файлы, а часть bash
- это то, что на самом деле выполняет переименование. С другой стороны, мы видим простую команду:
find -type f -exec <COMMAND> \;
Это находит только все файлы (без каталогов или символических ссылок) и вызывает некоторую другую команду всякий раз, когда находит файл. В этом случае у нас есть специальная КОМАНДА bash
.
Итак, что делает bash -c 'fp=$(dirname "$1");fn=$(basename "$fp");px="${1##*.}";mv "$1" "$fp"/"$fn"."$px"' sh "{}"
часть? Ну, прежде всего, узнайте структуру: bash -c 'command1;command2' arg0 arg1
. Всякий раз, когда используется флаг -c
, первый аргумент командной строки arg0
будет установлен как $0
, имя оболочки, поэтому оно не имеет значения, но важно "{}"
. Это цитируемый placeholder для имени файла, который find
будет передан как аргумент bash
.
С внутренней стороны команды bash мы извлекаем путь к файлу fp=$(dirname "$1")
, имя каталога fn=$(basename "$fp")
, и расширение файла или префикс px="${1##*.}"
. Все это отлично работает, так как мы запускаем команду из самого верхнего каталога (очень важно!). Наконец, mv "$1" "$fp"/"$fn"."$px"' sh "{}"
переименует исходный файл, который find
дал нам новое имя файла, которое мы создали с помощью "$fp"/"$fn"."$px"
, используя все эти переменные.
Тест команды выполняется в том же каталоге, что и раньше:
$ tree
.
├── Movie A (2014)
│ ├── filea.mkv
│ └── fileb.srt
└── Movie B (2016)
├── filea.mkv
└── fileb.srt
2 directories, 4 files
И если мы запустим команду, то с echo
вместо mv
мы увидим, что каждое имя файла будет переименовано соответственно.
$ find -type f -exec bash -c 'fp=$(dirname "$1");fn=$(basename "$fp");px="${1##*.}";echo "$1" "$fp"/"$fn"."$px"' sh ">
./Movie A (2014)/fileb.srt ./Movie A (2014)/Movie A (2014).srt
./Movie A (2014)/filea.mkv ./Movie A (2014)/Movie A (2014).mkv
./Movie B (2016)/fileb.srt ./Movie B (2016)/Movie B (2016).srt
./Movie B (2016)/filea.mkv ./Movie B (2016)/Movie B (2016).mkv
Помните: вышеприведенная команда использует echo
только для тестирования. Когда вы используете mv
, выхода нет, поэтому команда отключена.
. Вышеупомянутые два подхода используют рекурсивный обход дерева , Поскольку в вашем примере у вас есть только два уровня в дереве каталогов (каталог и файлы фильмов), мы можем упростить нашу предыдущую команду оболочки следующим образом:
for f in */* ;do fp=$(dirname "$f"); ext="${f##*.}" ; echo "$f" "$fp"/"$fp"."$ext" ;done
Опять же, ту же идею - замените echo
на mv
, когда вы уверены, что он работает правильно.
Результаты испытаний одинаковы:
$ tree
.
├── add_location_name.py
├── Movie A (2014)
│ ├── filea.mkv
│ └── fileb.srt
└── Movie B (2016)
├── filea.mkv
└── fileb.srt
2 directories, 5 files
$ for f in */* ;do fp=$(dirname "$f"); ext="${f##*.}" ; echo "$f" "$fp"/"$fp"."$ext" ;done
Movie A (2014)/filea.mkv Movie A (2014)/Movie A (2014).mkv
Movie A (2014)/fileb.srt Movie A (2014)/Movie A (2014).srt
Movie B (2016)/filea.mkv Movie B (2016)/Movie B (2016).mkv
Movie B (2016)/fileb.srt Movie B (2016)/Movie B (2016).srt
Существует несколько способов подхода к этому вопросу. Пожалуйста, внимательно прочитайте инструкции для получения наилучших результатов.
В этом ответе:
find
+ bash
подход Python - довольно мощный язык для системного администрирования, а перемещение дерева каталогов можно выполнить с помощью функции os.walk()
. В приведенном ниже скрипте мы делаем именно это: мы находим все файлы и работаем над каждым из них, определяя полный путь к каждому файлу, расширение файла и переименование его с помощью функции os.rename()
.
#!/usr/bin/env python3
import os,sys
def get_all_files(treeroot):
for dir,subdirs,files in os.walk(treeroot):
for f in files:
if f in __file__: continue
fullpath = os.path.realpath( os.path.join(dir,f) )
extension = fullpath.split('.')[-1]
newpath = os.path.join(dir, dir + '.' + extension)
print('Move ' + fullpath + ' to ' + newpath )
# os.rename(fullpath,newpath)
def main():
top_dir="."
# If directory not given, assume cwd
if len(sys.argv) == 2: top_dir=sys.argv[1]
get_all_files(top_dir)
if __name__ == '__main__' : main()
ПРИМЕЧАНИЕ. Очень важно, чтобы на самом деле переименовать файлы, которые необходимо удалить #
перед # os.rename(fullpath,newpath)
.
Используются все стандартные правила для сценариев: - сохранить его как add_location_name.py
в самом верхнем каталоге - сделать исполняемый файл с chmod +x ./add_location_name.py
- запустить с ./add_location_name.py
Вот пример того, как это работает на практике. Я создал каталог с двумя другими, Movie A (2016)
и Movie B (2016)
. Внутри они оба имеют два файла. Наш скрипт живет в том же каталоге:
$ tree
.
├── add_location_name.py
├── Movie A (2014)
│ ├── filea.mkv
│ └── fileb.srt
└── Movie B (2016)
├── filea.mkv
└── fileb.srt
Поэтому, когда мы запускаем скрипт, мы увидим следующий вывод:
$ ./add_location_name.py
Move /home/xieerqi/testdir/Movie A (2014)/fileb.srt to ./Movie A (2014)/./Movie A (2014).srt
Move /home/xieerqi/testdir/Movie A (2014)/filea.mkv to ./Movie A (2014)/./Movie A (2014).mkv
Move /home/xieerqi/testdir/Movie B (2016)/fileb.srt to ./Movie B (2016)/./Movie B (2016).srt
Move /home/xieerqi/testdir/Movie B (2016)/filea.mkv to ./Movie B (2016)/./Movie B (2016).mkv
find
полезно во многих отношениях, особенно при выполнении операций на нескольких уровнях дерева каталогов. В этом конкретном случае мы можем использовать его для фильтрации всех файлов и выполнить операцию переименования.
Прежде всего позвольте мне дать вам решение:
find -type f -exec bash -c 'fp=$(dirname "$1");fn=$(basename "$fp");px="${1##*.}";mv "$1" "$fp"/"$fn"."$px"' sh "{}" \;
Выглядит долго и страшно, не так ли? Но не беспокойтесь, давайте рассмотрим, как это работает.
Прежде всего вам нужно признать, что происходит две вещи: команда find
находит все файлы, а часть bash
- это то, что на самом деле выполняет переименование. С другой стороны, мы видим простую команду:
find -type f -exec <COMMAND> \;
Это находит только все файлы (без каталогов или символических ссылок) и вызывает некоторую другую команду всякий раз, когда находит файл. В этом случае у нас есть специальная КОМАНДА bash
.
Итак, что делает bash -c 'fp=$(dirname "$1");fn=$(basename "$fp");px="${1##*.}";mv "$1" "$fp"/"$fn"."$px"' sh "{}"
часть? Ну, прежде всего, узнайте структуру: bash -c 'command1;command2' arg0 arg1
. Всякий раз, когда используется флаг -c
, первый аргумент командной строки arg0
будет установлен как $0
, имя оболочки, поэтому оно не имеет значения, но важно "{}"
. Это цитируемый placeholder для имени файла, который find
будет передан как аргумент bash
.
С внутренней стороны команды bash мы извлекаем путь к файлу fp=$(dirname "$1")
, имя каталога fn=$(basename "$fp")
, и расширение файла или префикс px="${1##*.}"
. Все это отлично работает, так как мы запускаем команду из самого верхнего каталога (очень важно!). Наконец, mv "$1" "$fp"/"$fn"."$px"' sh "{}"
переименует исходный файл, который find
дал нам новое имя файла, которое мы создали с помощью "$fp"/"$fn"."$px"
, используя все эти переменные.
Тест команды выполняется в том же каталоге, что и раньше:
$ tree
.
├── Movie A (2014)
│ ├── filea.mkv
│ └── fileb.srt
└── Movie B (2016)
├── filea.mkv
└── fileb.srt
2 directories, 4 files
И если мы запустим команду, то с echo
вместо mv
мы увидим, что каждое имя файла будет переименовано соответственно.
$ find -type f -exec bash -c 'fp=$(dirname "$1");fn=$(basename "$fp");px="${1##*.}";echo "$1" "$fp"/"$fn"."$px"' sh ">
./Movie A (2014)/fileb.srt ./Movie A (2014)/Movie A (2014).srt
./Movie A (2014)/filea.mkv ./Movie A (2014)/Movie A (2014).mkv
./Movie B (2016)/fileb.srt ./Movie B (2016)/Movie B (2016).srt
./Movie B (2016)/filea.mkv ./Movie B (2016)/Movie B (2016).mkv
Помните: вышеприведенная команда использует echo
только для тестирования. Когда вы используете mv
, выхода нет, поэтому команда отключена.
. Вышеупомянутые два подхода используют рекурсивный обход дерева , Поскольку в вашем примере у вас есть только два уровня в дереве каталогов (каталог и файлы фильмов), мы можем упростить нашу предыдущую команду оболочки следующим образом:
for f in */* ;do fp=$(dirname "$f"); ext="${f##*.}" ; echo "$f" "$fp"/"$fp"."$ext" ;done
Опять же, ту же идею - замените echo
на mv
, когда вы уверены, что он работает правильно.
Результаты испытаний одинаковы:
$ tree
.
├── add_location_name.py
├── Movie A (2014)
│ ├── filea.mkv
│ └── fileb.srt
└── Movie B (2016)
├── filea.mkv
└── fileb.srt
2 directories, 5 files
$ for f in */* ;do fp=$(dirname "$f"); ext="${f##*.}" ; echo "$f" "$fp"/"$fp"."$ext" ;done
Movie A (2014)/filea.mkv Movie A (2014)/Movie A (2014).mkv
Movie A (2014)/fileb.srt Movie A (2014)/Movie A (2014).srt
Movie B (2016)/filea.mkv Movie B (2016)/Movie B (2016).mkv
Movie B (2016)/fileb.srt Movie B (2016)/Movie B (2016).srt
Существует несколько способов подхода к этому вопросу. Пожалуйста, внимательно прочитайте инструкции для получения наилучших результатов.
В этом ответе:
find
+ bash
подход Python - довольно мощный язык для системного администрирования, а перемещение дерева каталогов можно выполнить с помощью функции os.walk()
. В приведенном ниже скрипте мы делаем именно это: мы находим все файлы и работаем над каждым из них, определяя полный путь к каждому файлу, расширение файла и переименование его с помощью функции os.rename()
.
#!/usr/bin/env python3
import os,sys
def get_all_files(treeroot):
for dir,subdirs,files in os.walk(treeroot):
for f in files:
if f in __file__: continue
fullpath = os.path.realpath( os.path.join(dir,f) )
extension = fullpath.split('.')[-1]
newpath = os.path.join(dir, dir + '.' + extension)
print('Move ' + fullpath + ' to ' + newpath )
# os.rename(fullpath,newpath)
def main():
top_dir="."
# If directory not given, assume cwd
if len(sys.argv) == 2: top_dir=sys.argv[1]
get_all_files(top_dir)
if __name__ == '__main__' : main()
ПРИМЕЧАНИЕ. Очень важно, чтобы на самом деле переименовать файлы, которые необходимо удалить #
перед # os.rename(fullpath,newpath)
.
Используются все стандартные правила для сценариев: - сохранить его как add_location_name.py
в самом верхнем каталоге - сделать исполняемый файл с chmod +x ./add_location_name.py
- запустить с ./add_location_name.py
Вот пример того, как это работает на практике. Я создал каталог с двумя другими, Movie A (2016)
и Movie B (2016)
. Внутри они оба имеют два файла. Наш скрипт живет в том же каталоге:
$ tree
.
├── add_location_name.py
├── Movie A (2014)
│ ├── filea.mkv
│ └── fileb.srt
└── Movie B (2016)
├── filea.mkv
└── fileb.srt
Поэтому, когда мы запускаем скрипт, мы увидим следующий вывод:
$ ./add_location_name.py
Move /home/xieerqi/testdir/Movie A (2014)/fileb.srt to ./Movie A (2014)/./Movie A (2014).srt
Move /home/xieerqi/testdir/Movie A (2014)/filea.mkv to ./Movie A (2014)/./Movie A (2014).mkv
Move /home/xieerqi/testdir/Movie B (2016)/fileb.srt to ./Movie B (2016)/./Movie B (2016).srt
Move /home/xieerqi/testdir/Movie B (2016)/filea.mkv to ./Movie B (2016)/./Movie B (2016).mkv
find
полезно во многих отношениях, особенно при выполнении операций на нескольких уровнях дерева каталогов. В этом конкретном случае мы можем использовать его для фильтрации всех файлов и выполнить операцию переименования.
Прежде всего позвольте мне дать вам решение:
find -type f -exec bash -c 'fp=$(dirname "$1");fn=$(basename "$fp");px="${1##*.}";mv "$1" "$fp"/"$fn"."$px"' sh "{}" \;
Выглядит долго и страшно, не так ли? Но не беспокойтесь, давайте рассмотрим, как это работает.
Прежде всего вам нужно признать, что происходит две вещи: команда find
находит все файлы, а часть bash
- это то, что на самом деле выполняет переименование. С другой стороны, мы видим простую команду:
find -type f -exec <COMMAND> \;
Это находит только все файлы (без каталогов или символических ссылок) и вызывает некоторую другую команду всякий раз, когда находит файл. В этом случае у нас есть специальная КОМАНДА bash
.
Итак, что делает bash -c 'fp=$(dirname "$1");fn=$(basename "$fp");px="${1##*.}";mv "$1" "$fp"/"$fn"."$px"' sh "{}"
часть? Ну, прежде всего, узнайте структуру: bash -c 'command1;command2' arg0 arg1
. Всякий раз, когда используется флаг -c
, первый аргумент командной строки arg0
будет установлен как $0
, имя оболочки, поэтому оно не имеет значения, но важно "{}"
. Это цитируемый placeholder для имени файла, который find
будет передан как аргумент bash
.
С внутренней стороны команды bash мы извлекаем путь к файлу fp=$(dirname "$1")
, имя каталога fn=$(basename "$fp")
, и расширение файла или префикс px="${1##*.}"
. Все это отлично работает, так как мы запускаем команду из самого верхнего каталога (очень важно!). Наконец, mv "$1" "$fp"/"$fn"."$px"' sh "{}"
переименует исходный файл, который find
дал нам новое имя файла, которое мы создали с помощью "$fp"/"$fn"."$px"
, используя все эти переменные.
Тест команды выполняется в том же каталоге, что и раньше:
$ tree
.
├── Movie A (2014)
│ ├── filea.mkv
│ └── fileb.srt
└── Movie B (2016)
├── filea.mkv
└── fileb.srt
2 directories, 4 files
И если мы запустим команду, то с echo
вместо mv
мы увидим, что каждое имя файла будет переименовано соответственно.
$ find -type f -exec bash -c 'fp=$(dirname "$1");fn=$(basename "$fp");px="${1##*.}";echo "$1" "$fp"/"$fn"."$px"' sh ">
./Movie A (2014)/fileb.srt ./Movie A (2014)/Movie A (2014).srt
./Movie A (2014)/filea.mkv ./Movie A (2014)/Movie A (2014).mkv
./Movie B (2016)/fileb.srt ./Movie B (2016)/Movie B (2016).srt
./Movie B (2016)/filea.mkv ./Movie B (2016)/Movie B (2016).mkv
Помните: вышеприведенная команда использует echo
только для тестирования. Когда вы используете mv
, выхода нет, поэтому команда отключена.
. Вышеупомянутые два подхода используют рекурсивный обход дерева , Поскольку в вашем примере у вас есть только два уровня в дереве каталогов (каталог и файлы фильмов), мы можем упростить нашу предыдущую команду оболочки следующим образом:
for f in */* ;do fp=$(dirname "$f"); ext="${f##*.}" ; echo "$f" "$fp"/"$fp"."$ext" ;done
Опять же, ту же идею - замените echo
на mv
, когда вы уверены, что он работает правильно.
Результаты испытаний одинаковы:
$ tree
.
├── add_location_name.py
├── Movie A (2014)
│ ├── filea.mkv
│ └── fileb.srt
└── Movie B (2016)
├── filea.mkv
└── fileb.srt
2 directories, 5 files
$ for f in */* ;do fp=$(dirname "$f"); ext="${f##*.}" ; echo "$f" "$fp"/"$fp"."$ext" ;done
Movie A (2014)/filea.mkv Movie A (2014)/Movie A (2014).mkv
Movie A (2014)/fileb.srt Movie A (2014)/Movie A (2014).srt
Movie B (2016)/filea.mkv Movie B (2016)/Movie B (2016).mkv
Movie B (2016)/fileb.srt Movie B (2016)/Movie B (2016).srt
Существует несколько способов подхода к этому вопросу. Пожалуйста, внимательно прочитайте инструкции для получения наилучших результатов.
В этом ответе:
find
+ bash
подход Python - довольно мощный язык для системного администрирования, а перемещение дерева каталогов можно выполнить с помощью функции os.walk()
. В приведенном ниже скрипте мы делаем именно это: мы находим все файлы и работаем над каждым из них, определяя полный путь к каждому файлу, расширение файла и переименование его с помощью функции os.rename()
.
#!/usr/bin/env python3
import os,sys
def get_all_files(treeroot):
for dir,subdirs,files in os.walk(treeroot):
for f in files:
if f in __file__: continue
fullpath = os.path.realpath( os.path.join(dir,f) )
extension = fullpath.split('.')[-1]
newpath = os.path.join(dir, dir + '.' + extension)
print('Move ' + fullpath + ' to ' + newpath )
# os.rename(fullpath,newpath)
def main():
top_dir="."
# If directory not given, assume cwd
if len(sys.argv) == 2: top_dir=sys.argv[1]
get_all_files(top_dir)
if __name__ == '__main__' : main()
ПРИМЕЧАНИЕ. Очень важно, чтобы на самом деле переименовать файлы, которые необходимо удалить #
перед # os.rename(fullpath,newpath)
.
Используются все стандартные правила для сценариев: - сохранить его как add_location_name.py
в самом верхнем каталоге - сделать исполняемый файл с chmod +x ./add_location_name.py
- запустить с ./add_location_name.py
Вот пример того, как это работает на практике. Я создал каталог с двумя другими, Movie A (2016)
и Movie B (2016)
. Внутри они оба имеют два файла. Наш скрипт живет в том же каталоге:
$ tree
.
├── add_location_name.py
├── Movie A (2014)
│ ├── filea.mkv
│ └── fileb.srt
└── Movie B (2016)
├── filea.mkv
└── fileb.srt
Поэтому, когда мы запускаем скрипт, мы увидим следующий вывод:
$ ./add_location_name.py
Move /home/xieerqi/testdir/Movie A (2014)/fileb.srt to ./Movie A (2014)/./Movie A (2014).srt
Move /home/xieerqi/testdir/Movie A (2014)/filea.mkv to ./Movie A (2014)/./Movie A (2014).mkv
Move /home/xieerqi/testdir/Movie B (2016)/fileb.srt to ./Movie B (2016)/./Movie B (2016).srt
Move /home/xieerqi/testdir/Movie B (2016)/filea.mkv to ./Movie B (2016)/./Movie B (2016).mkv
find
полезно во многих отношениях, особенно при выполнении операций на нескольких уровнях дерева каталогов. В этом конкретном случае мы можем использовать его для фильтрации всех файлов и выполнить операцию переименования.
Прежде всего позвольте мне дать вам решение:
find -type f -exec bash -c 'fp=$(dirname "$1");fn=$(basename "$fp");px="${1##*.}";mv "$1" "$fp"/"$fn"."$px"' sh "{}" \;
Выглядит долго и страшно, не так ли? Но не беспокойтесь, давайте рассмотрим, как это работает.
Прежде всего вам нужно признать, что происходит две вещи: команда find
находит все файлы, а часть bash
- это то, что на самом деле выполняет переименование. С другой стороны, мы видим простую команду:
find -type f -exec <COMMAND> \;
Это находит только все файлы (без каталогов или символических ссылок) и вызывает некоторую другую команду всякий раз, когда находит файл. В этом случае у нас есть специальная КОМАНДА bash
.
Итак, что делает bash -c 'fp=$(dirname "$1");fn=$(basename "$fp");px="${1##*.}";mv "$1" "$fp"/"$fn"."$px"' sh "{}"
часть? Ну, прежде всего, узнайте структуру: bash -c 'command1;command2' arg0 arg1
. Всякий раз, когда используется флаг -c
, первый аргумент командной строки arg0
будет установлен как $0
, имя оболочки, поэтому оно не имеет значения, но важно "{}"
. Это цитируемый placeholder для имени файла, который find
будет передан как аргумент bash
.
С внутренней стороны команды bash мы извлекаем путь к файлу fp=$(dirname "$1")
, имя каталога fn=$(basename "$fp")
, и расширение файла или префикс px="${1##*.}"
. Все это отлично работает, так как мы запускаем команду из самого верхнего каталога (очень важно!). Наконец, mv "$1" "$fp"/"$fn"."$px"' sh "{}"
переименует исходный файл, который find
дал нам новое имя файла, которое мы создали с помощью "$fp"/"$fn"."$px"
, используя все эти переменные.
Тест команды выполняется в том же каталоге, что и раньше:
$ tree
.
├── Movie A (2014)
│ ├── filea.mkv
│ └── fileb.srt
└── Movie B (2016)
├── filea.mkv
└── fileb.srt
2 directories, 4 files
И если мы запустим команду, то с echo
вместо mv
мы увидим, что каждое имя файла будет переименовано соответственно.
$ find -type f -exec bash -c 'fp=$(dirname "$1");fn=$(basename "$fp");px="${1##*.}";echo "$1" "$fp"/"$fn"."$px"' sh ">
./Movie A (2014)/fileb.srt ./Movie A (2014)/Movie A (2014).srt
./Movie A (2014)/filea.mkv ./Movie A (2014)/Movie A (2014).mkv
./Movie B (2016)/fileb.srt ./Movie B (2016)/Movie B (2016).srt
./Movie B (2016)/filea.mkv ./Movie B (2016)/Movie B (2016).mkv
Помните: вышеприведенная команда использует echo
только для тестирования. Когда вы используете mv
, выхода нет, поэтому команда отключена.
. Вышеупомянутые два подхода используют рекурсивный обход дерева , Поскольку в вашем примере у вас есть только два уровня в дереве каталогов (каталог и файлы фильмов), мы можем упростить нашу предыдущую команду оболочки следующим образом:
for f in */* ;do fp=$(dirname "$f"); ext="${f##*.}" ; echo "$f" "$fp"/"$fp"."$ext" ;done
Опять же, ту же идею - замените echo
на mv
, когда вы уверены, что он работает правильно.
Результаты испытаний одинаковы:
$ tree
.
├── add_location_name.py
├── Movie A (2014)
│ ├── filea.mkv
│ └── fileb.srt
└── Movie B (2016)
├── filea.mkv
└── fileb.srt
2 directories, 5 files
$ for f in */* ;do fp=$(dirname "$f"); ext="${f##*.}" ; echo "$f" "$fp"/"$fp"."$ext" ;done
Movie A (2014)/filea.mkv Movie A (2014)/Movie A (2014).mkv
Movie A (2014)/fileb.srt Movie A (2014)/Movie A (2014).srt
Movie B (2016)/filea.mkv Movie B (2016)/Movie B (2016).mkv
Movie B (2016)/fileb.srt Movie B (2016)/Movie B (2016).srt
Существует несколько способов подхода к этому вопросу. Пожалуйста, внимательно прочитайте инструкции для получения наилучших результатов.
В этом ответе:
find
+ bash
подход Python - довольно мощный язык для системного администрирования, а перемещение дерева каталогов можно выполнить с помощью функции os.walk()
. В приведенном ниже скрипте мы делаем именно это: мы находим все файлы и работаем над каждым из них, определяя полный путь к каждому файлу, расширение файла и переименование его с помощью функции os.rename()
.
#!/usr/bin/env python3
import os,sys
def get_all_files(treeroot):
for dir,subdirs,files in os.walk(treeroot):
for f in files:
if f in __file__: continue
fullpath = os.path.realpath( os.path.join(dir,f) )
extension = fullpath.split('.')[-1]
newpath = os.path.join(dir, dir + '.' + extension)
print('Move ' + fullpath + ' to ' + newpath )
# os.rename(fullpath,newpath)
def main():
top_dir="."
# If directory not given, assume cwd
if len(sys.argv) == 2: top_dir=sys.argv[1]
get_all_files(top_dir)
if __name__ == '__main__' : main()
ПРИМЕЧАНИЕ. Очень важно, чтобы на самом деле переименовать файлы, которые необходимо удалить #
перед # os.rename(fullpath,newpath)
.
Используются все стандартные правила для сценариев: - сохранить его как add_location_name.py
в самом верхнем каталоге - сделать исполняемый файл с chmod +x ./add_location_name.py
- запустить с ./add_location_name.py
Вот пример того, как это работает на практике. Я создал каталог с двумя другими, Movie A (2016)
и Movie B (2016)
. Внутри они оба имеют два файла. Наш скрипт живет в том же каталоге:
$ tree
.
├── add_location_name.py
├── Movie A (2014)
│ ├── filea.mkv
│ └── fileb.srt
└── Movie B (2016)
├── filea.mkv
└── fileb.srt
Поэтому, когда мы запускаем скрипт, мы увидим следующий вывод:
$ ./add_location_name.py
Move /home/xieerqi/testdir/Movie A (2014)/fileb.srt to ./Movie A (2014)/./Movie A (2014).srt
Move /home/xieerqi/testdir/Movie A (2014)/filea.mkv to ./Movie A (2014)/./Movie A (2014).mkv
Move /home/xieerqi/testdir/Movie B (2016)/fileb.srt to ./Movie B (2016)/./Movie B (2016).srt
Move /home/xieerqi/testdir/Movie B (2016)/filea.mkv to ./Movie B (2016)/./Movie B (2016).mkv
find
полезно во многих отношениях, особенно при выполнении операций на нескольких уровнях дерева каталогов. В этом конкретном случае мы можем использовать его для фильтрации всех файлов и выполнить операцию переименования.
Прежде всего позвольте мне дать вам решение:
find -type f -exec bash -c 'fp=$(dirname "$1");fn=$(basename "$fp");px="${1##*.}";mv "$1" "$fp"/"$fn"."$px"' sh "{}" \;
Выглядит долго и страшно, не так ли? Но не беспокойтесь, давайте рассмотрим, как это работает.
Прежде всего вам нужно признать, что происходит две вещи: команда find
находит все файлы, а часть bash
- это то, что на самом деле выполняет переименование. С другой стороны, мы видим простую команду:
find -type f -exec <COMMAND> \;
Это находит только все файлы (без каталогов или символических ссылок) и вызывает некоторую другую команду всякий раз, когда находит файл. В этом случае у нас есть специальная КОМАНДА bash
.
Итак, что делает bash -c 'fp=$(dirname "$1");fn=$(basename "$fp");px="${1##*.}";mv "$1" "$fp"/"$fn"."$px"' sh "{}"
часть? Ну, прежде всего, узнайте структуру: bash -c 'command1;command2' arg0 arg1
. Всякий раз, когда используется флаг -c
, первый аргумент командной строки arg0
будет установлен как $0
, имя оболочки, поэтому оно не имеет значения, но важно "{}"
. Это цитируемый placeholder для имени файла, который find
будет передан как аргумент bash
.
С внутренней стороны команды bash мы извлекаем путь к файлу fp=$(dirname "$1")
, имя каталога fn=$(basename "$fp")
, и расширение файла или префикс px="${1##*.}"
. Все это отлично работает, так как мы запускаем команду из самого верхнего каталога (очень важно!). Наконец, mv "$1" "$fp"/"$fn"."$px"' sh "{}"
переименует исходный файл, который find
дал нам новое имя файла, которое мы создали с помощью "$fp"/"$fn"."$px"
, используя все эти переменные.
Тест команды выполняется в том же каталоге, что и раньше:
$ tree
.
├── Movie A (2014)
│ ├── filea.mkv
│ └── fileb.srt
└── Movie B (2016)
├── filea.mkv
└── fileb.srt
2 directories, 4 files
И если мы запустим команду, то с echo
вместо mv
мы увидим, что каждое имя файла будет переименовано соответственно.
$ find -type f -exec bash -c 'fp=$(dirname "$1");fn=$(basename "$fp");px="${1##*.}";echo "$1" "$fp"/"$fn"."$px"' sh ">
./Movie A (2014)/fileb.srt ./Movie A (2014)/Movie A (2014).srt
./Movie A (2014)/filea.mkv ./Movie A (2014)/Movie A (2014).mkv
./Movie B (2016)/fileb.srt ./Movie B (2016)/Movie B (2016).srt
./Movie B (2016)/filea.mkv ./Movie B (2016)/Movie B (2016).mkv
Помните: вышеприведенная команда использует echo
только для тестирования. Когда вы используете mv
, выхода нет, поэтому команда отключена.
. Вышеупомянутые два подхода используют рекурсивный обход дерева , Поскольку в вашем примере у вас есть только два уровня в дереве каталогов (каталог и файлы фильмов), мы можем упростить нашу предыдущую команду оболочки следующим образом:
for f in */* ;do fp=$(dirname "$f"); ext="${f##*.}" ; echo "$f" "$fp"/"$fp"."$ext" ;done
Опять же, ту же идею - замените echo
на mv
, когда вы уверены, что он работает правильно.
Результаты испытаний одинаковы:
$ tree
.
├── add_location_name.py
├── Movie A (2014)
│ ├── filea.mkv
│ └── fileb.srt
└── Movie B (2016)
├── filea.mkv
└── fileb.srt
2 directories, 5 files
$ for f in */* ;do fp=$(dirname "$f"); ext="${f##*.}" ; echo "$f" "$fp"/"$fp"."$ext" ;done
Movie A (2014)/filea.mkv Movie A (2014)/Movie A (2014).mkv
Movie A (2014)/fileb.srt Movie A (2014)/Movie A (2014).srt
Movie B (2016)/filea.mkv Movie B (2016)/Movie B (2016).mkv
Movie B (2016)/fileb.srt Movie B (2016)/Movie B (2016).srt
Существует несколько способов подхода к этому вопросу. Пожалуйста, внимательно прочитайте инструкции для получения наилучших результатов.
В этом ответе:
find
+ bash
подход Python - довольно мощный язык для системного администрирования, а перемещение дерева каталогов можно выполнить с помощью функции os.walk()
. В приведенном ниже скрипте мы делаем именно это: мы находим все файлы и работаем над каждым из них, определяя полный путь к каждому файлу, расширение файла и переименование его с помощью функции os.rename()
.
#!/usr/bin/env python3
import os,sys
def get_all_files(treeroot):
for dir,subdirs,files in os.walk(treeroot):
for f in files:
if f in __file__: continue
fullpath = os.path.realpath( os.path.join(dir,f) )
extension = fullpath.split('.')[-1]
newpath = os.path.join(dir, dir + '.' + extension)
print('Move ' + fullpath + ' to ' + newpath )
# os.rename(fullpath,newpath)
def main():
top_dir="."
# If directory not given, assume cwd
if len(sys.argv) == 2: top_dir=sys.argv[1]
get_all_files(top_dir)
if __name__ == '__main__' : main()
ПРИМЕЧАНИЕ. Очень важно, чтобы на самом деле переименовать файлы, которые необходимо удалить #
перед # os.rename(fullpath,newpath)
.
Используются все стандартные правила для сценариев: - сохранить его как add_location_name.py
в самом верхнем каталоге - сделать исполняемый файл с chmod +x ./add_location_name.py
- запустить с ./add_location_name.py
Вот пример того, как это работает на практике. Я создал каталог с двумя другими, Movie A (2016)
и Movie B (2016)
. Внутри они оба имеют два файла. Наш скрипт живет в том же каталоге:
$ tree
.
├── add_location_name.py
├── Movie A (2014)
│ ├── filea.mkv
│ └── fileb.srt
└── Movie B (2016)
├── filea.mkv
└── fileb.srt
Поэтому, когда мы запускаем скрипт, мы увидим следующий вывод:
$ ./add_location_name.py
Move /home/xieerqi/testdir/Movie A (2014)/fileb.srt to ./Movie A (2014)/./Movie A (2014).srt
Move /home/xieerqi/testdir/Movie A (2014)/filea.mkv to ./Movie A (2014)/./Movie A (2014).mkv
Move /home/xieerqi/testdir/Movie B (2016)/fileb.srt to ./Movie B (2016)/./Movie B (2016).srt
Move /home/xieerqi/testdir/Movie B (2016)/filea.mkv to ./Movie B (2016)/./Movie B (2016).mkv
find
полезно во многих отношениях, особенно при выполнении операций на нескольких уровнях дерева каталогов. В этом конкретном случае мы можем использовать его для фильтрации всех файлов и выполнить операцию переименования.
Прежде всего позвольте мне дать вам решение:
find -type f -exec bash -c 'fp=$(dirname "$1");fn=$(basename "$fp");px="${1##*.}";mv "$1" "$fp"/"$fn"."$px"' sh "{}" \;
Выглядит долго и страшно, не так ли? Но не беспокойтесь, давайте рассмотрим, как это работает.
Прежде всего вам нужно признать, что происходит две вещи: команда find
находит все файлы, а часть bash
- это то, что на самом деле выполняет переименование. С другой стороны, мы видим простую команду:
find -type f -exec <COMMAND> \;
Это находит только все файлы (без каталогов или символических ссылок) и вызывает некоторую другую команду всякий раз, когда находит файл. В этом случае у нас есть специальная КОМАНДА bash
.
Итак, что делает bash -c 'fp=$(dirname "$1");fn=$(basename "$fp");px="${1##*.}";mv "$1" "$fp"/"$fn"."$px"' sh "{}"
часть? Ну, прежде всего, узнайте структуру: bash -c 'command1;command2' arg0 arg1
. Всякий раз, когда используется флаг -c
, первый аргумент командной строки arg0
будет установлен как $0
, имя оболочки, поэтому оно не имеет значения, но важно "{}"
. Это цитируемый placeholder для имени файла, который find
будет передан как аргумент bash
.
С внутренней стороны команды bash мы извлекаем путь к файлу fp=$(dirname "$1")
, имя каталога fn=$(basename "$fp")
, и расширение файла или префикс px="${1##*.}"
. Все это отлично работает, так как мы запускаем команду из самого верхнего каталога (очень важно!). Наконец, mv "$1" "$fp"/"$fn"."$px"' sh "{}"
переименует исходный файл, который find
дал нам новое имя файла, которое мы создали с помощью "$fp"/"$fn"."$px"
, используя все эти переменные.
Тест команды выполняется в том же каталоге, что и раньше:
$ tree
.
├── Movie A (2014)
│ ├── filea.mkv
│ └── fileb.srt
└── Movie B (2016)
├── filea.mkv
└── fileb.srt
2 directories, 4 files
И если мы запустим команду, то с echo
вместо mv
мы увидим, что каждое имя файла будет переименовано соответственно.
$ find -type f -exec bash -c 'fp=$(dirname "$1");fn=$(basename "$fp");px="${1##*.}";echo "$1" "$fp"/"$fn"."$px"' sh ">
./Movie A (2014)/fileb.srt ./Movie A (2014)/Movie A (2014).srt
./Movie A (2014)/filea.mkv ./Movie A (2014)/Movie A (2014).mkv
./Movie B (2016)/fileb.srt ./Movie B (2016)/Movie B (2016).srt
./Movie B (2016)/filea.mkv ./Movie B (2016)/Movie B (2016).mkv
Помните: вышеприведенная команда использует echo
только для тестирования. Когда вы используете mv
, выхода нет, поэтому команда отключена.
. Вышеупомянутые два подхода используют рекурсивный обход дерева , Поскольку в вашем примере у вас есть только два уровня в дереве каталогов (каталог и файлы фильмов), мы можем упростить нашу предыдущую команду оболочки следующим образом:
for f in */* ;do fp=$(dirname "$f"); ext="${f##*.}" ; echo "$f" "$fp"/"$fp"."$ext" ;done
Опять же, ту же идею - замените echo
на mv
, когда вы уверены, что он работает правильно.
Результаты испытаний одинаковы:
$ tree
.
├── add_location_name.py
├── Movie A (2014)
│ ├── filea.mkv
│ └── fileb.srt
└── Movie B (2016)
├── filea.mkv
└── fileb.srt
2 directories, 5 files
$ for f in */* ;do fp=$(dirname "$f"); ext="${f##*.}" ; echo "$f" "$fp"/"$fp"."$ext" ;done
Movie A (2014)/filea.mkv Movie A (2014)/Movie A (2014).mkv
Movie A (2014)/fileb.srt Movie A (2014)/Movie A (2014).srt
Movie B (2016)/filea.mkv Movie B (2016)/Movie B (2016).mkv
Movie B (2016)/fileb.srt Movie B (2016)/Movie B (2016).srt
Учитывая
$ tree
.
└── A
├── B
│ ├── somefile
│ ├── T.txt
│ ├── X.srt
│ └── Z.mkv
└── C
├── somefile
├── T.txt
├── W.mkv
└── Y.srt
3 directories, 8 files
, тогда
$ find A -type f \( -name '*.mkv' -o -name '*.srt' \) -not -name '.*' -exec sh -c '
for f; do
dir="${f%/*}" ; ext="${f##*.}" ; new="${dir##*/}"
echo mv -- "$f" "${dir}/${new}.${ext}"
done' sh {} +
mv -- A/C/Y.srt A/C/C.srt
mv -- A/C/W.mkv A/C/C.mkv
mv -- A/B/Z.mkv A/B/B.mkv
mv -- A/B/X.srt A/B/B.srt
(удалите echo, как только вы убедитесь, что он будет делать то, что вы хотите).
Учитывая
$ tree
.
└── A
├── B
│ ├── somefile
│ ├── T.txt
│ ├── X.srt
│ └── Z.mkv
└── C
├── somefile
├── T.txt
├── W.mkv
└── Y.srt
3 directories, 8 files
, тогда
$ find A -type f \( -name '*.mkv' -o -name '*.srt' \) -not -name '.*' -exec sh -c '
for f; do
dir="${f%/*}" ; ext="${f##*.}" ; new="${dir##*/}"
echo mv -- "$f" "${dir}/${new}.${ext}"
done' sh {} +
mv -- A/C/Y.srt A/C/C.srt
mv -- A/C/W.mkv A/C/C.mkv
mv -- A/B/Z.mkv A/B/B.mkv
mv -- A/B/X.srt A/B/B.srt
(удалите echo, как только вы убедитесь, что он будет делать то, что вы хотите).
Учитывая
$ tree
.
└── A
├── B
│ ├── somefile
│ ├── T.txt
│ ├── X.srt
│ └── Z.mkv
└── C
├── somefile
├── T.txt
├── W.mkv
└── Y.srt
3 directories, 8 files
, тогда
$ find A -type f \( -name '*.mkv' -o -name '*.srt' \) -not -name '.*' -exec sh -c '
for f; do
dir="${f%/*}" ; ext="${f##*.}" ; new="${dir##*/}"
echo mv -- "$f" "${dir}/${new}.${ext}"
done' sh {} +
mv -- A/C/Y.srt A/C/C.srt
mv -- A/C/W.mkv A/C/C.mkv
mv -- A/B/Z.mkv A/B/B.mkv
mv -- A/B/X.srt A/B/B.srt
(удалите echo, как только вы убедитесь, что он будет делать то, что вы хотите).
Учитывая
$ tree
.
└── A
├── B
│ ├── somefile
│ ├── T.txt
│ ├── X.srt
│ └── Z.mkv
└── C
├── somefile
├── T.txt
├── W.mkv
└── Y.srt
3 directories, 8 files
, тогда
$ find A -type f \( -name '*.mkv' -o -name '*.srt' \) -not -name '.*' -exec sh -c '
for f; do
dir="${f%/*}" ; ext="${f##*.}" ; new="${dir##*/}"
echo mv -- "$f" "${dir}/${new}.${ext}"
done' sh {} +
mv -- A/C/Y.srt A/C/C.srt
mv -- A/C/W.mkv A/C/C.mkv
mv -- A/B/Z.mkv A/B/B.mkv
mv -- A/B/X.srt A/B/B.srt
(удалите echo, как только вы убедитесь, что он будет делать то, что вы хотите).