创建单独的文本文件来列出每个目录和子目录中的内容

创建单独的文本文件来列出每个目录和子目录中的内容

我有一个根文件夹,其中有许多目录和文件。我需要保存每个子目录中名为的内容列表list.txt

假设我有

A
|
-----B
|    |---Z
|    |---a.txt
|    |---b.jpg
|
|
|----C
|    |--a.txt
|    |--b.txt

运行该命令它应该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'

但我不知道如何单独保存内容。

请提出一些建议。

答案1

下面的脚本将添加一个列表到所有以递归方式从目录中获取目录:

#!/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 添加到所有子目录. 如果你也需要或想要在主要的请提及您的目录的 (root)-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")+","

注意缩进,将替换项放在完全相同的位置

答案2

为了使其递归,首先打开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

答案3

单行版本

首先使用find来获取目录,然后 shell 为您完成工作:

$ 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$0bash$1find
  • bash将进入给定的目录并使用find参数- maxdepth 1将该命令限制在该子目录中。-not -name "."将排除.目录链接,即对自身的引用。
  • 接下来,我们将文本传递给awk,它的作用只是删除,给出的最后一个,find以便我们得到一个有效的 CSV 列表。请注意使用双引号和\$。这是为了简化引用并防止 bash 将其解释$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

相关内容