2012-02-22 13 views
5

Il pigro me sta pensando di aggiungere una colonna ad alcuni file di testo.Usa il nome della cartella come una colonna in un file di testo

I file di testo sono in directory e vorrei aggiungere il nome della directory al file di testo.

Come il file di testo text.txt nella cartella the_peasant:

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

sarebbe diventato:

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

allora ho i file di testo simili in altre cartelle chiamate "the_king", ecc

Penso che questa sia una combinazione del comando find, bash scripting e sed, ma non riesco a vederlo. Qualche idea?

+2

Il pigro mi sta suggerendo di pubblicare del codice per indicare che hai almeno fatto un po 'di lavoro su questo. –

risposta

1

L'albero delle directory:

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

Directory e contenuto prima:

% 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 

Codice (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 

quali uscite:

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 

Directory e contenuti dopo:

% 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 

Questo è stato divertente! Grazie per la sfida!

+0

Grazie, l'ho usato con piccole modifiche. Speravo di imparare da un copione bash o da/sed/awk su un solo liner, ma questo era troppo allettante. – AWE

+0

Fantastico, sono contento che tu l'abbia trovato utile! :) Gli one-liner hanno il loro posto, ma gli script sono per sempre. – jathanism

0

Vorrei.

  • ottenere il percorso del file ad esempio fpath = "example.txt"
  • trovare la directory del file utilizzando il seguito
  • leggere il file e scrivere in un nuovo file aggiungendo dir_name alla riga appena letta prima di scrivere

Accedere alla directory può essere fatto utilizzando

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

Stai usando lo script nella cartella appropriata? Quindi puoi usare il modulo os per trovare la cartella corrente. Diciamo che voleva prendere solo la fine della struttura di directory, si potrebbe usare os.path, come:

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

semplice script Python per questo (dovrebbe funzionare da qualsiasi cartella, fino a quando si passa il fullpath al file di destinazione, ovviamente):

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

Supponendo che i tuoi file siano abbastanza piccoli da essere interamente tenuti in memoria –

1

Ecco quello che mi si avvicinò con:

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

Ecco un esempio di come i comandi sarebbero costruite, assumendo i seguenti file esiste:

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

Il primo find /home/the_peasant -type f restituisce tali file esattamente come sopra.

Avanti, il comando sed sarebbe uscita un nome di file, seguito dal nome della directory, in questo modo:

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

I xargs sarebbe di gruppo ogni due linee e passarli al comando sh, in modo da finirebbe con i seguenti tre comandi:

$ 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 

E infine questo si tradurrà nelle seguenti comandi sed, che si andranno ad aggiungere il nome della cartella all'inizio di ogni riga:

$ 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

Modifica: notato che qualcosa non era corretto. Ho rimosso il loop dir - il suo cammino ricorsivo ora. Ci scusiamo per il disguido.

Utilizzando 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() 

uscita:

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

obbligatorio singolo rivestimento usando find e 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 

Considerando una perl e sed sono nel $ PATH. Genera un file di comandi sed per eseguire il cambiamento effettivo in modo da poter esaminare ciò che deve essere fatto.

Nella mia prova, che file di comando si presenta in questo modo:

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

Ottieni un +1 per quella copertina, perché ...Beh, sì – jathanism

+1

Sì, pensavo che one-liners e perl fossero entrambi sottorappresentati, così ho deciso di uccidere due piccioni con una fava. – kbenson

0

Ecco un one-ish-liner in bash e 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

Questo potrebbe funzionare per voi:

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

o se avete GNU sed:

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

BELLISSIMO !!! (brutta sintassi, ma comunque eccezionale) – AWE

+0

Ora è una dolce fodera. – jathanism

Problemi correlati