2012-02-22 15 views
5

Leniwy ja myśli o dodaniu kolumny do niektórych plików tekstowych.Użyj nazwy folderu jako kolumny w pliku tekstowym.

Pliki tekstowe są w katalogach i chciałbym dodać nazwę katalogu do pliku tekstowego.

Podobnie jak plik tekstowy text.txt w folderze the_peasant:

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

stałby się:

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

to mam podobne pliki tekstowe w innych folderach zwanych "the_king" itd

Myślę, że jest to kombinacja polecenia find, skryptów bash i sed, ale nie mogę tego zobaczyć. Jakieś pomysły?

+2

leniwy mnie sugeruje, żebyś napisał jakiś kod, aby wskazać, że przynajmniej wykonałeś jakąś pracę nad tym. –

Odpowiedz

1

drzewie katalogów:

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

katalogów i zawartość przed:

% 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 

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

które wyjścia:

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 

katalogów i zawartość po:

% 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 

To była zabawa! Dzięki za wyzwanie!

+0

Dzięki, użyłem go z drobnymi zmianami. Miałem nadzieję, że dowiem się ze skryptu z basha lub z jednego kliknięcia, ale to było zbyt kuszące. – AWE

+0

Awesome Cieszę się, że znalazłeś to przydatne! :) One-liners mają swoje miejsce, ale skrypty są na zawsze. – jathanism

0

Chciałbym.

  • uzyskać ścieżkę np fpath = „example.txt”
  • znaleźć katalogu tego pliku przy użyciu poniżej
  • przeczytać w pliku i zapis do nowego pliku dołączanie DIR_NAME z rzędu po prostu czytać przed napisaniem.

Dostęp do katalogu można zrobić za pomocą

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

Czy uruchomienie skryptu w odpowiednim folderze? Następnie możesz użyć modułu os, aby znaleźć bieżący folder. Powiedzmy, że chciał wziąć tylko koniec drzewie katalogów, można użyć os.path, jak:

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

prosty skrypt Pythona do tego (powinien pracować z dowolnego folderu, tak długo, jak przejść do fullpath docelowego pliku, oczywiście):

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

Zakładając, że twoje pliki są wystarczająco małe, aby je w całości przechowywać w pamięci –

1

Oto co wymyśliłem:

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

Oto przykład jak komendy będzie skonstruowany przy założeniu, że istnieją następujące pliki:

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

Najpierw find /home/the_peasant -type f wypisze te pliki dokładnie tak, jak powyżej.

Następnie sed poleceń byłoby wyjście nazwę pliku, a następnie nazwy katalogów, tak:

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

W xargs przysłuży się grupy każdych dwóch linii i przekazać je do polecenia sh, więc nie skończy się z trzech następujących poleceń:

$ 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 

i ostatecznie spowoduje następujących sed poleceń, które doda nazwę folderu na początku każdej linii:

$ 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

Edytuj: zauważyłeś, że coś jest nie w porządku. Usunąłem pętlę dir - teraz rekurencyjnie chodzę. Przepraszamy za pomyłkę.

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

wyjściowa:

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

Obowiązkowe pojedynczej wkładki przy użyciu znaleźć i 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 

Zakłada perla i sed są w $ PATH. Generuje plik poleceń sed, aby dokonać rzeczywistej zmiany, aby można było sprawdzić, co należy zrobić.

W moim teście, że plik polecenia wygląda tak:

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

Otrzymujesz +1 dla tej jednej linijki, ponieważ ...Cóż, tak – jathanism

+1

Tak, myślałem, że jedno-liniowce i perl były niedostatecznie reprezentowane, więc postanowiłem zabić dwie pieczenie na jednym ogniu. – kbenson

0

Oto jeden-owski-liner w bash i 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

To może pracować dla Ciebie:

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

lub jeśli masz GNU sed:

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

PIĘKNE !!! (brzydka składnia, ale nadal świetna) – AWE

+0

Teraz to dziwaczny "słodki". – jathanism

Powiązane problemy