6

ls の結果を変更する bash エイリアスを作成しようとしています。私は常に、同じ命名規則に従っていない大量のファイルを処理しています。それらについての唯一の共通点は、番号が 4 で埋められており (正しい言い方がわからないので申し訳ありません)、拡張子の直前にあることです。

例 - filename_v028_0392.bgeo、test_x34.prerun.0012.simdata、filename_v001_0233.exr

シーケンスをそれぞれ 1 つの要素としてリストしたいので、

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

の行に沿って何かとして表示されます

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

まだ変更されていない非シーケンスをリストしています。

どこからこれに取り組み始めればよいのか、本当にわかりません。私はかなりの量のpythonを知っていますが、それが本当に最善の方法であるかどうかはわかりません. どんな助けでも大歓迎です!

ありがとう

4

2 に答える 2

2

これは、でそのようなことを行う1つの方法ですawk。ただし、コードはかなり判読できません。

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

ls同じフォルダでの上記の出力とスクリプトの比較:

etuardu@subranu:~/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
etuardu@subranu:~/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
etuardu@subranu:~/Desktop/pippo$ 

例で提供した構文に固執する場合は、この出力をにパイプすることができますsed。いくつかの正規表現の魔法であなたは持っています:

etuardu@subranu:~/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)
etuardu@subranu:~/Desktop/pippo$

次に、bashスクリプトにまとめて入れ、エイリアスを定義し~/.bashrcて呼び出すことができます。

ちなみに、これはほとんどの* nixシステムで実行できるような純粋なbash風のソリューションですが、使用するツールはこのタスクにはあまり適していません。このスクリプトは、python読みやすさ、高レベルの文字列操作、およびパターンマッチング機能を利用するなどの言語で作成することを検討してください。

于 2012-10-13T19:09:17.020 に答える
2

シーケンス番号によってのみ変更される複数の行を折りたたむというより一般的な問題を解決することにより、問題を解決するpython 2.7スクリプトを取得しました

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

つまり、あなたのデータでは:

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

これは、数字以外のテキストに一致する 2 つの連続する行に存在する整数の違いに基づいています。これにより、シーケンスの基礎として使用されるフィールドの変更時に、不均一な入力を処理できます...

入力の例を次に示します。

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

これは次を与えます:

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

どんなコメントでも大歓迎です!

はあ...忘れていました。引数がなければ、このスクリプトは現在のディレクトリの折りたたまれた内容を出力します。

于 2012-10-14T00:00:41.230 に答える