2012-10-13 10 views
6

Sto cercando di creare un alias bash che cambierà i risultati di ls. Mi occupo costantemente di sequenze di file di grandi dimensioni, che non seguono le stesse convenzioni di denominazione. L'unica cosa comune su di loro è che il numero è 4 (non mi spiace molto sul modo corretto di dirlo) e precede immediatamente l'estensione.Alias ​​Bash per rilevare automaticamente sequenze di file con nome arbitrario?

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

desidero per le sequenze per essere incluso ciascun elemento come 1, in modo che

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 

sarebbe visualizzato come somethign lungo le linee di

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

mentre continua a elencare le sequenze non inalterate.

Non sono davvero sicuro da dove iniziare ad avvicinarmi. Conosco una quantità decente di pitone, ma non sono sicuro che sarebbe davvero il modo migliore per farlo. Qualsiasi aiuto sarebbe molto apprezzato!

Grazie

+0

Bella domanda! Vuoi anche la colorazione? : p E quanto lontano vuoi andare con questo? Voglio dire, cosa vuoi fare con qualcosa come 'file1-001-1.txt-0',' file1-001-1.txt-1', ..., 'file1-001-2.txt-0 ',' file1-001-2.txt-1', ..., 'file1-002-1.txt-0',' file1-002-1.txt-1', ... Sarà più difficile per riconoscere o rappresentare rispetto alle sequenze che hai dato a –

+0

Per quanto sia bello che funzioni sempre, ho solo bisogno che funzioni nella situazione che ho postato, * ####. estensione. Non sono sicuro se questo è qualcosa che dovrei fare in Python o Straight Bash. Conosco solo un po 'di battuta e il tipo di volevo usare questo come punto di partenza per imparare meglio però. – phimath

+0

un altro problema però è che non tutte le estensioni che uso sono 3 caratteri, e alcuni di essi hanno. Sono in essi, come 'bgeo.gz'. Potrei fare una lista di tutte le estensioni che uso, ma mi piacerebbe trovare una soluzione più elegante, come ad esempio prendere le ultime 4 cifre numeriche. – phimath

risposta

2

ho ottenuto un 2,7 script python che risolve il problema risolvendo il problema più generale di crollare diverse linee che cambiano solo da un numero di sequenza

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 

cioè sui tuoi dati:

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 

Si basa sulle differenze tra gli interi presenti in due righe consecutive che corrispondono al testo non numerico. Ciò consente di gestire input non uniformi, sulle modifiche del campo utilizzato come base per la sequenza ...

Ecco un esempio di ingresso:

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 

che dà:

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

Ogni commento è il benvenuto!

Hah ... I nearby forgot: senza argomenti, questo script restituisce il contenuto collassato della directory corrente.

+0

grazie! c'è molto qui dentro, non mi è familiare, ma sto iniziando a scavare e imparare. Grazie! – phimath

+0

nessun problema! btw, 'sorted()' la directory che elenca perché 'os.listdir()' restituisce i file in un ordine arbitrario –

2

questo è un modo di fare qualcosa di simile con awk. Codice è abbastanza illeggibile però:

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

Confrontando l'uscita del ls e lo script sopra nella stessa cartella:

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

Se vi occupate di attenersi alla sintassi che hai fornito nell'esempio, è possibile pipe questa uscita a sed. Con un po 'di magia regex avete:

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

allora si può mettere tutto in uno script bash e definire un alias nel ~/.bashrc chiamarlo.

Come nota a margine, si consideri che questa è una pura soluzione bash-ish che dovrebbe essere eseguita sulla maggior parte dei sistemi * nix, ma gli strumenti utilizzati non sono realmente adatti all'attività. Potresti considerare di scrivere questo script in un linguaggio come python per sfruttare la sua leggibilità e le funzioni di manipolazione delle stringhe e di corrispondenza dei modelli di livello superiore.

+0

grazie! Cercherò di farlo in python ma un giorno tornerò per cercare di capirlo. – phimath

Problemi correlati