4 votos

Crear archivo de texto separado para listar el contenido de cada directorio y subdirectorio

Tengo una carpeta de la root y en la que hay muchos directorios más los archivos. Necesito guardar una lista de los contenidos en cada subdirectorio con el nombre list.txt.

Supongamos que tengo

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

Ejecuta el comando que se debe dar una list.txt en cada subdirectorio con contenidos separados por comas.

Tengo # comentó lo que el contenido debe ser...

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

Lo más cercano que podría llegar a la lista de los archivos es

find . -maxdepth n -type f -printf '%f\n'

pero no sé cómo guardar el contenido por separado.

Por favor, sugiera algo.

5voto

Jacob Vlijm Puntos 24137

La secuencia de comandos a continuación va a añadir una lista de todos los sub- directorios de un directorio de forma recursiva:

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

El uso de

  1. Copie la secuencia de comandos en un archivo vacío, guárdelo como dirlists.py
  2. Ejecutar con el principal directorio como argumento:

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

Nota

Como se ha mencionado, el script agrega una list.txt a todos los subdirectorios. Si usted también necesita o quiere tener una lista en la principal (root) -dir de su directorio, favor de mencionar.

Explicación

  1. Lista (caminando) todos los directorios de forma recursiva dentro de un directorio:

    for root, dirs, files in os.walk(sys.argv[1]):
        for dr in dirs:
            dr = os.path.join(root, dr)
    
  2. Crear una lista de contenido para cada uno de ellos:

    os.listdir(dr)
    
  3. Abierto (crear si es necesario) el archivo de texto y escribir la lista de contenido, excluyendo posibles anterior archivos con el nombre list.txt:

    open(os.path.join(dr, "list.txt"), "wt").write(
        ",".join(f for f in os.listdir(dr) if f != "list.txt")
        )
    

EDITAR

Como se pide en un comentario:

En caso de que necesite la línea en list.txt , para terminar con una coma, simplemente reemplazar:

",".join(f for f in os.listdir(dr) if f != "list.txt")

por:

",".join(f for f in os.listdir(dr) if f != "list.txt")+","

la mente de la hendidura, el lugar de reemplazo en la misma posición exacta

4voto

Zanna Puntos 502

Para hacerlo recursivo, primero encienda globstar

shopt -s globstar

Luego, en el directorio padre (A en su estructura), puede ejecutar:

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

o un poco más readably

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

que, si el directorio a contiene

├── a
│   ├── 1.txt
│   ├── 2.txt
│   ├── 3.txt
│   ├── a badly named file &
│   └── Z

se creará una lista en el directorio a que se parece a esto:

2.txt,1.txt,3.txt,Z,a badly named file &

find no produce ordenó la salida, así que si eso es un problema voy a tener que pensar de una mejor manera. El \( -not -name "list.txt" \) en la find de expresión es para evitar que la lista de incluyéndose a sí misma, y el sed expresión es puramente para quitar el punto y coma final. La vergüenza acerca de todos los bytes adicionales.

Puede que desee desactivar globstar cuando se hace

shopt -u globstar

3voto

Serg Puntos 17677

One-liner versión

Uso find obtener primero los directorios, entonces el shell de hacer el trabajo por usted:

$ 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

La forma en que esto funciona:

  • utilizamos find comando con -type d a filtrar todos los directorios
  • -exec declaración \; terminador nos permite ejecutar un comando específico para cada argumento de que find obtiene
  • dentro de -exec corremos bash con -c flag , a la que le pasaremos $0 argumento bash y $1 argumento de que el directorio que outter find encuentran
  • bash entrará en el directorio determinado y uso find con - maxdepth 1 argumento para limitar ese comando solo a ese subdirectorio. -not -name "." excluye la . directorio de enlace , que es la referencia a sí mismo.
  • A continuación, vamos a pasar el texto a awk, que sólo sirve para quitar el último , dado por find , así que tenemos un válido lista CSV. Nota el uso de comillas dobles y \$. Que está destinado a simplificar la comilla y evita bash de interpretar $0 como sus propios argumentos posicionales, sino más bien como awk comando.
  • De toda la lista de elementos que interior find obtiene será enviado a list.txt través > redirección.

Una mejora adicional a esto podría ser la utilización de -not -name "list.txt" dentro de la interna find comando para excluir de la lista de archivos (ya que debido a la > siempre creando el archivo para escribir en primer lugar, list.txt también aparecerá en la lista).

Personalmente, si yo fuera a hacer esto por mí mismo, yo iba a escribir la lista de archivos con \0 separador para evitar lidiar con la difícil nombres de archivo, pero que también requiere recordar que list.txt en \0 formato y redacción de un analizador de función.

Completa versión del script

En aras de la legibilidad, he aquí un completo script de la versión en lugar de una sola línea.

Secuencia de comandos:

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

Tenga en cuenta que este script se ejecuta desde el directorio superior. También se incluye en la lista si se almacena en el mismo directorio. Si se coloca a ~/bin por ejemplo (o cualquier otro directorio que pertenece a $PATH variable), y la ejecución, el nombre de secuencia de comandos no aparecen en la lista.

Prueba :

$ 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

EnMiMaquinaFunciona.com

EnMiMaquinaFunciona es una comunidad de administradores de sistemas en la que puedes resolver tus problemas y dudas.
Puedes consultar las preguntas de otros sysadmin, hacer tus propias preguntas o resolver las de los demás.

Powered by: