Создайте отдельный текстовый файл для списка содержания в каждом каталоге и подкаталоге

У меня есть корневая папка и в этом существует много каталогов плюс файлы. Я должен сохранить список содержания в каждом подкаталоге с именем 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'

но я не знаю, как сохранить содержание отдельно.

Предложите что-то.

4
задан 2 April 2017 в 01:12

3 ответа

Сценарий ниже добавит список ко всем под - директора из каталога рекурсивно:

#!/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")
            )

Использовать

  1. Скопируйте сценарий в пустой файл, сохраните его как dirlists.py
  2. Выполните его с основным каталогом как аргумент:

    python3 /path/to/dirlists.py /path/to/maindirectory
    

Примечание:

Как упомянуто, сценарий добавляет list.txt ко всему subdirs. Если Вы также нуждаетесь или хотите иметь список в основном (корень) - dir Вашего каталога, упомяните.

Объяснение

  1. Список (идут через), все каталоги рекурсивно в каталоге:

    for root, dirs, files in os.walk(sys.argv[1]):
        for dr in dirs:
            dr = os.path.join(root, dr)
    
  2. Создайте список содержания для каждого из них:

    os.listdir(dr)
    
  3. Открытый (создают при необходимости) текстовый файл и пишет перечисленное содержание, исключая возможные более ранние названные файлы 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")+","

возражайте против добавления отступа, поместите замену в том же самом положении

5
ответ дан 23 November 2019 в 11:41

Для создания этого рекурсивным сначала включите 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
4
ответ дан 23 November 2019 в 11:41

Версия остроты

Использовать 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 locaed
  • bash введет данный каталог и использование 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
3
ответ дан 23 November 2019 в 11:41

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

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