2012-10-13 11 views
6

Ich bin auf der Suche nach einem Bash Alias, der die Ergebnisse von ls ändern wird. Ich beschäftige mich ständig mit großen Sequenzen von Dateien, die nicht den gleichen Namenskonventionen folgen. Die einzige Gemeinsamkeit bei ihnen ist, dass die Nummer 4 gepolstert ist (tut mir leid, nicht wirklich sicher, wie das zu sagen ist) und geht der Erweiterung unmittelbar voraus.Bash-Alias, um beliebig benannte Dateisequenzen automatisch zu erkennen?

zB - filename_v028_0392.bgeo, test_x34.prerun.0012.simdata, filename_v001_0233.exr

I würden für die Sequenzen mögen jeweils als Element 1 aufgeführt werden, so daß

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 

wäre angezeigt als etwas entlang der Linien von

[seq]filename_v003_####.geo (1-7) 
[seq]filename_v003_####.geo (32-36) 
[seq]testxxtest.####.exr (57-63) 

während noch nicht Sequenzen nicht unverändert aufgeführt.

Ich bin mir wirklich nicht sicher, wo ich anfangen soll. Ich kenne eine anständige Menge Python, bin mir aber nicht sicher, ob das wirklich der beste Weg wäre. Jede Hilfe würde sehr geschätzt werden!

Dank

+0

Nette Frage! Willst du auch die Färbung? : p Und wie weit willst du damit gehen? Ich meine, was willst du mit etwas wie 'Datei1-001-1.txt-0',' Datei1-001-1.txt-1', ..., 'Datei1-001-2.txt-0 machen ',' file1-001-2.txt-1', ..., 'file1-002-1.txt-0',' file1-002-1.txt-1', ... Das wird schwieriger zu erkennen oder zu repräsentieren als die Sequenzen, die Sie gaben –

+0

So cool wie es wäre, damit immer zu arbeiten, ich brauche es wirklich nur in der Situation zu arbeiten, die ich gepostet habe, * ####. Erweiterung. Ich bin mir nicht sicher, ob das etwas ist, was ich in Python oder Straight Bash machen sollte. Ich kenne nur ein bisschen Bash und wollte das als Ausgangspunkt nutzen, um es besser zu lernen. – phimath

+0

ein anderes Problem ist jedoch, dass nicht alle Erweiterungen, die ich verwende, 3 Zeichen sind, und einige von ihnen haben .s in ihnen, wie 'bgeo.gz'. Ich könnte eine Liste aller Erweiterungen erstellen, die ich verwende, aber ich würde gerne eine elegantere Lösung finden, wie zum Beispiel die letzten 4 Ziffern. – phimath

Antwort

2

Ich habe ein Python-2.7-Skript, das durch die Lösung des allgemeineren Problems einsturz mehrere Zeilen zu ändern nur durch eine Sequenznummer

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 

, dass Ihr Problem löst, ist, auf Ihre Daten:

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 

Es basiert auf den Unterschieden zwischen den Ganzzahlen, die in zwei aufeinanderfolgenden Zeilen vorhanden sind, die mit dem Nicht-Ziffern-Text übereinstimmen. Dies ermöglicht es, mit ungleichmäßigen Eingaben umzugehen, bei Änderungen des Feldes, das als Grundlage für die Sequenz verwendet wird ...

Hier ist ein Beispiel von Eingabe:

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 

die gibt:

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

Jeder Kommentar ist willkommen!

Hah ... Ich habe in der Nähe vergessen: ohne Argumente, dieses Skript gibt den minimierten Inhalt des aktuellen Verzeichnisses aus.

+0

danke! Es gibt eine Menge hier drin, mit denen ich nicht vertraut bin, aber ich fange an, durchzugraben und zu lernen. Vielen Dank! – phimath

+0

kein Problem! btw, 'sorted()' die Verzeichnisliste, weil 'os.listdir()' die Dateien in einer beliebigen Reihenfolge zurückgibt –

2

Dies ist ein Weg mit awk so etwas zu tun. Code ist ziemlich unlesbar aber:

#!/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(); 
}' 

Vergleicht man die Ausgabe von ls und das Skript oben auf dem gleichen Ordner:

[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$ 

Wenn Sie die Syntax, die Sie in dem gegebenen Beispiel bleiben dagegen haben, können Sie Pipe diesen Ausgang zu sed. Mit einigen regex Magie haben Sie:

[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$ 

Dann können Sie ganz in einem Bash-Skript setzen und einen Alias ​​in Ihrem ~/.bashrc definieren es zu nennen.

Als eine Nebenbemerkung, bedenken Sie, dass dies eine solche reine bash-ish-Lösung ist, die auf den meisten * nix-Systemen laufen sollte, aber die verwendeten Tools sind nicht wirklich für die Aufgabe geeignet. Sie können erwägen, dieses Skript in eine Sprache wie python zu schreiben, um seine Lesbarkeit und höhere String-Manipulation und Pattern-Matching-Funktionen zu nutzen.

+0

danke! Ich werde versuchen, es in Python zu tun, werde aber eines Tages wiederkommen, um das zu versuchen und zu verstehen. – phimath