2012-10-13 16 views
6

Szukam, aby utworzyć alias bash, który zmieni wyniki ls. Ciągle mam do czynienia z dużymi sekwencjami plików, które nie są zgodne z tymi samymi konwencjami nazewnictwa. Jedyną powszechną rzeczą jest to, że liczba ta wynosi 4 (nie jest to naprawdę pewny poprawnego sposobu) i natychmiast poprzedza rozszerzenie.Alias ​​bash do automatycznego wykrywania dowolnie nazwanych sekwencji plików?

przykład - filename_v028_0392.bgeo, test_x34.prerun.0012.simdata, filename_v001_0233.exr

ja jak dla sekwencji wymienić każdy jako 1 elementu tak, że

filename_v003_0001.geo 
filename_v003_0002.geo 
filename_v003_0003.geo 
filename_v003_0004.geo 
filename_v003_0005.geo 
filename_v003_0006.geo 
filename_v003_0007.geo 
filename_v003_0032.geo 
filename_v003_0033.geo 
filename_v003_0034.geo 
filename_v003_0035.geo 
filename_v003_0036.geo 
testxxtest.0057.exr 
testxxtest.0058.exr 
testxxtest.0059.exr 
testxxtest.0060.exr 
testxxtest.0061.exr 
testxxtest.0062.exr 
testxxtest.0063.exr 

byłoby wyświetlane jako coś, co jest nadal zgodne z ciągiem niezmienionych ciągów.

Nie jestem pewien, od czego zacząć. Znam przyzwoitą ilość pythona, ale nie jestem pewien, czy to byłby najlepszy sposób, aby to osiągnąć. Każda pomoc będzie bardzo ceniona!

Dzięki

+0

Ładne pytanie! Czy chcesz także kolorowania? : p Jak daleko chcesz się posunąć? Chodzi mi o to, co chcesz zrobić z czymś w rodzaju 'file1-001-1.txt-0',' file1-001-1.txt-1', ..., 'file1-001-2.txt-0 ',' plik1-001-2.txt-1', ..., 'plik1-002-1.txt-0',' plik1-002-1.txt-1', ... To będzie trudniejsze rozpoznawać lub reprezentować niż sekwencje, które dałeś –

+0

Tak fajne, jak by to działało zawsze, naprawdę potrzebuję go tylko do pracy w sytuacji, którą zamieściłem, * ####. extension. Po prostu nie jestem pewien, czy to jest coś, co powinienem zrobić w pythonie lub prostym bashu. Znam tylko trochę bash i chciałbym użyć tego jako punktu wyjścia, aby lepiej się uczyć. – phimath

+0

Innym problemem jest jednak to, że nie wszystkie z rozszerzeń, których używam, to 3 znaki, a niektóre z nich mają w sobie takie znaki, jak "bgeo.gz". Mogę sporządzić listę wszystkich rozszerzeń, których używam, ale chciałbym znaleźć bardziej eleganckie rozwiązanie, takie jak ostatnie 4 cyfry. – phimath

Odpowiedz

2

Mam Pythona 2.7 skrypt, który rozwiązuje problem przez rozwiązanie bardziej ogólny problem zawaleniem kilka linii zmieniających się tylko przez kilka sekwencji

import re 

def do_compress(old_ints, ints): 
    """ 
    whether the ints of the current entry is the continuation of the previous 
    entry 
    returns a list of the indexes to compress, or [] or False when the current 
    line is not part of an indexed sequence 
    """ 
    return len(old_ints) == len(ints) and \ 
     [i for o, n, i in zip(old_ints, ints, xrange(len(ints))) if n - o == 1] 

def basic_format(file_start, file_stop): 
    return "[seq]{} .. {}".format(file_start, file_stop) 


def compress(files, do_compress=do_compress, seq_format=basic_format): 
    p = None 
    old_ints =() 
    old_indexes =() 

    seq_and_files_list = [] 
     # list of file names or dictionaries that represent sequences: 
     # {start, stop, start_f, stop_f} 

    for f in files: 
     ints =() 
     indexes =() 

     m = p is not None and p.match(f) # False, None, or a valid match 
     if m: 
      ints = [int(x) for x in m.groups()] 
      indexes = do_compress(old_ints, ints) 

     # state variations 
     if not indexes: # end of sequence or no current sequence 
      p = re.compile(\ 
       '(\d+)'.join(re.escape(x) for x in re.split('\d+',f)) + '$') 
      m = p.match(f) 
      old_ints = [int(x) for x in m.groups()] 
      old_indexes =() 
      seq_and_files_list.append(f) 

     elif indexes == old_indexes: # the sequence continues 
      seq_and_files_list[-1]['stop'] = old_ints = ints 
      seq_and_files_list[-1]['stop_f'] = f 
      old_indexes = indexes 

     elif old_indexes ==(): # sequence started on previous filename 
      start_f = seq_and_files_list.pop() 
      s = {'start': old_ints, 'stop': ints, \ 
       'start_f': start_f, 'stop_f': f} 
      seq_and_files_list.append(s) 

      old_ints = ints 
      old_indexes = indexes 

     else: # end of sequence, but still matches previous pattern 
      old_ints = ints 
      old_indexes =() 
      seq_and_files_list.append(f) 

    return [ isinstance(f, dict) and seq_format(f['start_f'], f['stop_f']) or f 
     for f in seq_and_files_list ] 


if __name__ == "__main__": 
    import sys 
    if len(sys.argv) == 1: 
     import os 
     lst = sorted(os.listdir('.')) 
    elif sys.argv[1] in ("-h", "--help"): 
     print """USAGE: {} [FILE ...] 
compress the listing of the current directory, or the content of the files by 
collapsing identical lines, except for a sequence number 
""" 
     sys.exit(0) 
    else: 
     import string 
     lst = [string.rstrip(l, '\r\n') for f in sys.argv[1:] for l in open(f)]) 
    for x in compress(lst): 
     print x 

To znaczy, na swoje dane:

bernard $ ./ls_sequence_compression.py given_data 
[seq]filename_v003_0001.geo .. filename_v003_0007.geo 
[seq]filename_v003_0032.geo .. filename_v003_0036.geo 
[seq]testxxtest.0057.exr .. testxxtest.0063.exr 

Opiera się na różnicach między liczbami całkowitymi występującymi w dwóch kolejnych wierszach pasujących do tekstu niepustego. Pozwala to na radzenie sobie z nierównomiernymi danymi wejściowymi, zmianami pola używanego jako podstawa sekwencji ...

Oto przykład wejścia:

01 - test8.txt 
01 - test9.txt 
01 - test10.txt 
02 - test11.txt 
02 - test12.txt 
03 - test13.txt 
04 - test13.txt 
05 - test13.txt 
06 
07 
08 
09 
10 

co daje:

[seq]01 - test8.txt .. 01 - test10.txt 
[seq]02 - test11.txt .. 02 - test12.txt 
[seq]03 - test13.txt .. 05 - test13.txt 
[seq]06 .. 10 

Każdy komentarz jest mile widziany!

Hah ... W pobliżu zapomniałem: bez argumentów, ten skrypt wyświetla zwiniętą zawartość bieżącego katalogu.

+0

dziękuję! jest tu wiele rzeczy, których nie znam, ale zaczynam się przekopywać i uczyć się. dzięki! – phimath

+0

bez problemu! btw, 'sorted()' listing katalogu, ponieważ 'os.listdir()' zwraca pliki w dowolnej kolejności –

2

Jest to jeden ze sposobów na osiągnięcie czegoś takiego z awk. Kod jest dość nieczytelny choć:

#!/bin/bash 

ls | awk ' 
function smprint() { 
    if ((a[1]!=exA1) || (a[2] != exA2+1)) { 
     if ((exA1) && (exA1==exexA1)) print "\t.. " exfile; 
     else printf linesep; 
     if ($0!=exfile) printf $0; 
    } 
}; 
BEGIN { d="[0-9]"; rg="(.*)(" d d d d ")(.*)"; }; 
{ 
    split(gensub(rg, "\\1####\\3\t\\2", "g"), a, "\t"); 
    # produces e.g.: a[1]="file####.ext" a[2]="0001" 

    smprint(); 
    linesep="\n"; 

    exexA1=exA1; # old old a[1] 
    exA1=a[1]; # old a[1] 
    exA2=a[2]; # old a[2] 
    exfile=$0; # old filename 
}; 
END { 
    smprint(); 
}' 

Porównując wyjście ls i skrypt powyżej w tym samym folderze:

[email protected]:~/Desktop/pippo$ ls 
asd1234_0001.tar.bz2 filename_v003_0006.geo script.sh 
asd1234_0002.tar.bz2 filename_v003_0007.geo testxxtest.0057.exr 
asd1234_0003.tar.bz2 filename_v003_0032.geo testxxtest.0058.exr 
filename_v003_0001.geo filename_v003_0033.geo testxxtest.0059.exr 
filename_v003_0002.geo filename_v003_0034.geo testxxtest.0060.exr 
filename_v003_0003.geo filename_v003_0035.geo testxxtest.0061.exr 
filename_v003_0004.geo filename_v003_0036.geo testxxtest.0062.exr 
filename_v003_0005.geo other_file    testxxtest.0063.exr 
[email protected]:~/Desktop/pippo$ ./script.sh 
asd1234_0001.tar.bz2 .. asd1234_0003.tar.bz2 
filename_v003_0001.geo .. filename_v003_0007.geo 
filename_v003_0032.geo .. filename_v003_0036.geo 
other_file 
script.sh 
testxxtest.0057.exr .. testxxtest.0063.exr 
[email protected]:~/Desktop/pippo$ 

Jeśli nic się trzymać składni podany w przykładzie, można wyprowadź to wyjście do sed. Z pewnym regex magii masz:

[email protected]:~/Desktop/pippo$ ./script.sh | sed -r 's/(.*)([0-9]{4})([^\t]+)\t\.\. .*([0-9]{4}).*$/[seq]\1####\3 (\2-\4)/g' 
[seq]asd1234_####.tar.bz2 (0001-0003) 
[seq]filename_v003_####.geo (0001-0007) 
[seq]filename_v003_####.geo (0032-0036) 
other_file 
script.sh 
[seq]testxxtest.####.exr (0057-0063) 
[email protected]:~/Desktop/pippo$ 

Następnie można umieścić całkowicie w skrypcie bash i zdefiniowania aliasu w ~/.bashrc to nazwać.

Jako uwagę dodatkową należy wziąć pod uwagę, że jest to tak proste, bashowe rozwiązanie, które powinno działać na większości systemów * nix, ale używane narzędzia nie są odpowiednie do tego zadania. Możesz rozważyć napisanie tego skryptu w języku takim jak python, aby zyskać na jego czytelności i wyższym poziomie manipulacji ciągami i funkcjami dopasowywania wzorca.

+0

dziękuję! Mam zamiar zrobić to w pythonie, ale kiedyś wrócę, aby spróbować to zrozumieć. – phimath

Powiązane problemy