2012-02-22 14 views
5

El perezoso está pensando en agregar una columna a algunos archivos de texto.Utilice el nombre de la carpeta como columna en un archivo de texto

Los archivos de texto están en directorios y me gustaría agregar el nombre del directorio al archivo de texto.

Al igual que el archivo de texto en la carpeta text.txtthe_peasant:

has a wart  
was dressed up like a witch  
has a false nose 

se convertiría en:

the_peasant has a wart  
the_peasant was dressed up like a witch  
the_peasant has a false nose 

entonces he archivos de texto similares en otras carpetas llamadas "the_king", etc.

Creo que esta es una combinación del comando find, bash scripting y sed, pero no puedo verlo terminado. ¿Algunas ideas?

+2

El Lazy me sugiere que publiques un código para indicar que al menos has hecho algún trabajo al respecto. –

Respuesta

1

El árbol de directorios:

% tree . 
. 
├── the_king 
│   └── text.txt 
├── the_knight 
│   └── text.txt 
├── the_peasant 
│   └── text.txt 
└── wart.py 
3 directories, 4 files 

Directorios y contenido antes:

% find . -name 'text.txt' -print -exec cat {} \;  
./the_king/text.txt 
has a wart  
was dressed up like a witch  
has a false nose 
./the_knight/text.txt 
has a wart  
was dressed up like a witch  
has a false nose 
./the_peasant/text.txt 
has a wart  
was dressed up like a witch  
has a false nose 

Código (wart.py):

#!/usr/bin/env python 

import os 

text_file = 'text.txt' 
cwd = os.path.curdir # '.' 

# Walk thru each directory starting at '.' and if the directory contains 
# 'text.txt', print each line of the file prefixed by the name containing 
# directory. 
for root, dirs, files in os.walk(cwd): 
    if text_file in files: # We only care IF the file is in this directory. 
     print 'Found %s!' % root 
     filepath = os.path.join(root, text_file) # './the_peasant/text.txt' 
     root_base = os.path.basename(root)  # './the_peasant' => 'the_peasant' 
     output = '' 
     with open(filepath, 'r') as reader:  # Open file for read/write 
      for line in reader:     # Iterate the lines of the file 
       new_line = "%s %s" % (root_base, line) 
       print new_line, 
       output += new_line    # Append to the output 

     with open(filepath, 'w') as writer: 
      writer.write(output)     # Write to the file 

     print 

que da salida:

Found ./the_king! 
the_king has a wart  
the_king was dressed up like a witch  
the_king has a false nose 

Found ./the_knight! 
the_knight has a wart  
the_knight was dressed up like a witch  
the_knight has a false nose 

Found ./the_peasant! 
the_peasant has a wart  
the_peasant was dressed up like a witch  
the_peasant has a false nose 

Directorios y contenido después:

% find . -name 'text.txt' -print -exec cat {} \; 
./the_king/text.txt 
the_king has a wart  
the_king was dressed up like a witch  
the_king has a false nose 
./the_knight/text.txt 
the_knight has a wart  
the_knight was dressed up like a witch  
the_knight has a false nose 
./the_peasant/text.txt 
the_peasant has a wart  
the_peasant was dressed up like a witch  
the_peasant has a false nose 

Esto fue muy divertido! Gracias por el desafío!

+0

Gracias, lo usé con cambios menores. Esperaba aprender de un script de bash o de un trazador de líneas per/sed/awk one, pero esto era demasiado tentador. – AWE

+0

Impresionante ¡Me alegra que lo haya encontrado útil! :) Los One-Liners tienen su lugar, pero los scripts son para siempre. – jathanism

0

Lo haría.

  • obtener la ruta del archivo, por ejemplo fpath = "example.txt"
  • encontrar el directorio de ese archivo mediante el siguiente
  • leer en el archivo y escribir en un archivo nuevo añadiendo nombre_dir a la fila acaba de leer antes de escribir.

Acceso al directorio se puede hacer mediante el uso de

import os 
fpath = "example.txt" 
dir_name = os.path.dirname(fpath) 
0

¿Está ejecutando la secuencia de comandos en la carpeta correspondiente? Luego puede usar el módulo os para encontrar la carpeta actual. Digamos que quería tomar sólo el final del árbol de directorios, puede utilizar os.path, como:

import os, os.path 

curDirectory = os.getcwd() 
baseDir = os.path.basename() 

inFile = open("filename.txt").xreadlines() 
outFile = open("filename.out", "w") 

for line in inFile: 
    outFile.write("%s %s" % (baseDir, line)) 
outFile.close() 
1

simple script en Python para este (debería funcionar desde cualquier carpeta, el tiempo que se pasa la ruta completa a la archivo de destino, obviamente):

#!/usr/bin/python 
if __name__ == '__main__': 
    import sys 
    import os 

    # Get full filepath and directory name 
    filename = os.path.abspath(sys.argv[1]) 
    dirname = os.path.split(os.path.dirname(filename))[1] 

    # Read current file contents 
    my_file = open(filename, 'r') 
    lines = my_file.readlines() 
    my_file.close() 

    # Rewrite lines, adding folder name to the start 
    output_lines = [dirname + ' ' + line for line in lines] 
    my_file = open(filename, 'w') 
    my_file.write('\n'.join(output_lines)) 
    my_file.close() 
+0

Suponiendo que sus archivos son lo suficientemente pequeños como para guardarse por completo en la memoria –

1

Esto es lo que ocurrió:

find /path/to/dir -type f | sed -r 'p;s:.*/(.*)/.*:\1:' | xargs -n 2 sh -c 'sed -i "s/^/$1 /" $0' 

Aquí es un ejemplo de cómo se construyen los comandos, asumiendo los siguientes archivos existen:

/home/the_peasant/a.txt 
/home/the_peasant/b.txt 
/home/the_peasant/farmer/c.txt 

Primero find /home/the_peasant -type f generará esos archivos exactamente como se indicó anteriormente.

A continuación, el comando sed sería la salida un nombre de archivo, seguido por el nombre del directorio, así:

/home/the_peasant/a.txt 
the_peasant 
/home/the_peasant/b.txt 
the_peasant 
/home/the_peasant/farmer/c.txt 
farmer 

Los xargs agrupara cada dos líneas y pasarlos al comando sh, por lo que terminaría con los tres comandos siguientes:

$ sh -c 'sed -i "s/^/$1 /" $0' /home/the_peasant/a.txt the_peasant 
$ sh -c 'sed -i "s/^/$1 /" $0' /home/the_peasant/b.txt the_peasant 
$ sh -c 'sed -i "s/^/$1 /" $0' /home/the_peasant/farmer/c.txt farmer 

Y finalmente esto se traducirá en los siguientes comandos sed que se sumarán el nombre de carpeta al inicio de cada línea:

$ sed -i "s/^/the_peasant /" /home/the_peasant/a.txt 
$ sed -i "s/^/the_peasant /" /home/the_peasant/b.txt 
$ sed -i "s/^/farmer /" /home/the_peasant/farmer/c.txt 
0

Editar: notado que algo no era correcto. Quité el bucle dir - ahora camina recursivamente. Perdón por la confusión.

Usando os.walk

import os.path 
directory = os.path.curdir 
pattern = ".py"; 
for (path,dirs,files) in os.walk(directory): 
    for file in files: 
     if not file.endswith(pattern): 
      continue 
     filename = os.path.join(path,file) 
     #print "file: ",filename 
     #continue 
     with open(filename,"r") as f: 
      for line in f.readlines(): 
       print "{0} {1}".format(filename,line) 
      f.close() 

Salida:

list1.py # LAB(replace solution) 
list1.py # return 
list1.py # LAB(end solution) 
1

obligatorio solo revestimiento usando buscar y Perl

find . -maxdepth 1 -mindepth 1 -type d | perl -MFile::Basename -ne 'chomp; my $dir = basename($_); for my $file (glob "$dir/*") { print qq{sed -i "s/^/$dir /" $file\n} }' | tee rename_commands.sh 

sh rename_commands.sh 

Asume Perl y sed son en su $ PATH. Genera un archivo de comandos sed para hacer el cambio real para que pueda revisar lo que se debe hacer.

En mi prueba, ese archivo de comandos se ve así:

sed -i "s/^/foo /" foo/text1 
sed -i "s/^/foo /" foo/text2 
sed -i "s/^/bar /" bar/belvedere 
sed -i "s/^/bar /" bar/robin 
+0

Obtiene un +1 por ese trazador, porque ...Bueno, sí – jathanism

+1

Sí, pensé que one-liners y perl estaban poco representados, así que decidí matar dos pájaros de un tiro. – kbenson

0

Aquí es una pregunta-ish-liner en bash y awk:

find . -type f -print0 | 
while read -r -d "" path; do 
    mv "$path" "$path.bak" 
    awk -v dir="$(basename "$(dirname "$path")")" '{print dir, $0}' "$path.bak" > "$path" 
done 
3

Esto podría funcionar para usted:

find . -name text.txt | sed 's|.*/\(.*\)/.*|sed -i "[email protected]^@\1 @" & |' | sh 

o si tiene sed de GNU:

find . -name text.txt | sed 's|.*/\(.*\)/.*|sed -i "[email protected]^@\1 @" & |e' 
+0

HERMOSO !!! (sintaxis fea, pero sigue siendo genial) – AWE

+0

Ahora que es un maldito dulce de una sola línea. – jathanism

Cuestiones relacionadas