У меня есть корневая папка и в этом существует много каталогов плюс файлы. Я должен сохранить список содержания в каждом подкаталоге с именем list.txt
.
Предположим, что я имею
A
|
-----B
| |---Z
| |---a.txt
| |---b.jpg
|
|
|----C
| |--a.txt
| |--b.txt
При выполнении команды это должно дать a list.txt
в каждом подкаталоге с содержанием, разделенным запятыми.
У меня есть #, прокомментированный, каково содержание должно быть...
A
|
-----B
| |---Z
| |---a.txt
| |---b.jpg
| |---list.txt # Z,a.txt,b.jpg
|
|
|----C
| |--a.txt
| |--b.txt
| |--list.txt # a.txt,b.txt
Самое близкое, которое я мог получить для списка файлов,
find . -maxdepth n -type f -printf '%f\n'
но я не знаю, как сохранить содержание отдельно.
Предложите что-то.
Сценарий ниже добавит список ко всем под - директора из каталога рекурсивно:
#!/usr/bin/env python3
import os
import sys
for root, dirs, files in os.walk(sys.argv[1]):
for dr in dirs:
dr = os.path.join(root, dr)
open(os.path.join(dr, "list.txt"), "wt").write(
",".join(f for f in os.listdir(dr) if f != "list.txt")
)
dirlists.py
Выполните его с основным каталогом как аргумент:
python3 /path/to/dirlists.py /path/to/maindirectory
Как упомянуто, сценарий добавляет list.txt ко всему subdirs. Если Вы также нуждаетесь или хотите иметь список в основном (корень) - dir Вашего каталога, упомяните.
Список (идут через), все каталоги рекурсивно в каталоге:
for root, dirs, files in os.walk(sys.argv[1]):
for dr in dirs:
dr = os.path.join(root, dr)
Создайте список содержания для каждого из них:
os.listdir(dr)
Открытый (создают при необходимости) текстовый файл и пишет перечисленное содержание, исключая возможные более ранние названные файлы list.txt
:
open(os.path.join(dr, "list.txt"), "wt").write(
",".join(f for f in os.listdir(dr) if f != "list.txt")
)
Согласно просьбе в комментарии:
В случае, если Вам нужна строка в list.txt
для окончания запятой просто замените:
",".join(f for f in os.listdir(dr) if f != "list.txt")
:
",".join(f for f in os.listdir(dr) if f != "list.txt")+","
возражайте против добавления отступа, поместите замену в том же самом положении
Для создания этого рекурсивным сначала включите globstar
shopt -s globstar
Затем в родительском каталоге (A
в структуре), можно работать:
for d in **; do [[ -d "$d" ]] && (find "$d" -mindepth 1 -maxdepth 1 \( -not -name "list.txt" \) -printf '%f,' | sed 's/,$/\n/') |tee "$d"/list.txt ; done
или немного больше четко
for d in **; do
[[ -d "$d" ]] &&
(find "$d" -mindepth 1 -maxdepth 1 \( -not -name "list.txt" \) -printf '%f,' | sed 's/,$/\n/') | tee "$d"/list.txt
done
, который, если каталог a
содержит
├── a
│ ├── 1.txt
│ ├── 2.txt
│ ├── 3.txt
│ ├── a badly named file &
│ └── Z
, создаст список в каталоге a
, который похож на это:
2.txt,1.txt,3.txt,Z,a badly named file &
find
не производит заказанный, производят, поэтому если это - проблема, я должен буду думать о лучшем пути. \( -not -name "list.txt" \)
в find
выражение должно препятствовать тому, чтобы список включал себя, и sed
, выражение должно просто удалить запаздывающую запятую. Позор обо всех тех дополнительных байтах.
можно хотеть выключить globstar
, когда сделано
shopt -u globstar
Использовать find
для получения каталогов сначала затем окружите, делают работу для Вас:
$ tree
.
├── a_directory
│ ├── a_file
│ ├── a_subdir
│ └── mv-files.py
└── another_dir
├── {file}1
└── {file}2
3 directories, 4 files
$ find -type d -exec bash -c 'cd $1; find -maxdepth 1 -not -name "." -not -name "list.txt" -printf "%f," | awk "{print substr(\$0,0,length(\$0)-1)}" > list.txt' bash "{}" \;
$ cat a_directory/list.txt
mv-files.py,a_file,list.txt,a_subdir
Путем это работает:
find
команда с -type d
отфильтровывать все каталоги-exec
оператор с \;
разделитель позволяет нам выполнять указанную команду для каждого аргумента это find
получает-exec
мы работаем bash
с -c
флаг, которому мы передаем $0
аргумент bash
и $1
причем аргументом является каталог что внешний find
locaedbash
введет данный каталог и использование find
с - maxdepth 1
аргумент для ограничения той команды только тем подкаталогом. -not -name "."
исключит .
ссылка каталога, которая является ссылкой на сам. awk
, который служит только для удаления последнего ,
данный find
так, чтобы у нас был действительный список CSV. Отметьте использование двойных кавычек и \$
. Это предназначено для упрощения заключения в кавычки и препятствует тому, чтобы удар интерпретировал $0
как его собственные позиционные параметры, а скорее как awk
команда. find
получает будет отправлен в list.txt
через >
перенаправление.Дополнительное улучшение этого могло быть должно использовать -not -name "list.txt"
во внутреннем find
команда для исключения самого файла списка (потому что из-за >
всегда создавая файл для записи сначала, list.txt
также появится в списке).
Лично, если бы я делал это для меня, то я написал бы список файлов с \0
разделитель, чтобы не иметь дело с трудными именами файлов, но это также требует запоминания это list.txt
находится в \0
формат и запись синтаксического анализатора функционируют для него.
Ради удобочитаемости вот полная версия сценария вместо остроты.
Сценарий:
#!/bin/bash
# note : this assumes you run the script from top-most directory
find -type d | while IFS= read -r directory;
do
cd "$directory"
find -maxdepth 1 -not -name "." -not -name "list.txt" -printf "%f," |
awk "{print substr(\$0,0,length(\$0)-1)}" > list.txt
cd - > /dev/null
done
Обратите внимание, что этот скрипт запущен от каталога самого верхнего уровня. Это также включает сам в список, если это хранится в том же каталоге. Если Вы помещаете его в ~/bin
например (или любой другой каталог, который принадлежит $PATH
переменная), и выполненный это, название сценария не появится в списке.
Тест:
$ tree
.
├── a_directory
│ ├── a_file
│ ├── a_subdir
│ └── mv-files.py
├── another_dir
│ ├── {file}1
│ └── {file}2
└── make_lists.sh
3 directories, 5 files
$ ./make_lists.sh
$ tree
.
├── a_directory
│ ├── a_file
│ ├── a_subdir
│ │ └── list.txt
│ ├── list.txt
│ └── mv-files.py
├── another_dir
│ ├── {file}1
│ ├── {file}2
│ └── list.txt
├── list.txt
└── make_lists.sh
3 directories, 9 files
$ cat a_directory/list.txt
mv-files.py,a_file,a_subdir