challenge 手作業Grep

標準入力を読み込んで、行選択のUIをだし、選択されたものだけを標準出力にだしてください。 標準出力に出力するタイミングは選択終了をユーザーが報告したときです。(完了ボタンを想定してください)

UIライブラリは何をつかってもかまいません。 例えばncursesのようなコンソール上でのUIでもかまいませんし、GtkのようなGUIライブラリでもかまいません。

想定される使い方としては、以下のような感じです。

ps aux | handgrep | xargs kill -9

プロセスの一覧を表示、UI上で選択したものをkill

Posted feedbacks - Nested

Flatten Hidden
F# で、作ってみました。
(FSharpSamplesのEditor.fsで、RichTextBoxをListBox に変更したもの)
コンパイルは、
fsc HandGrep.fs -g
--target:winexe にしてしまうと、stdin は、取れてもstdout が、出力されなくなるので、注意。
空行は無視される
使用例:
>dir /B | HandGrep
handgrep.exe
handgrep.fs
File メニューからQuit した場合stdoutに書き出す。
×(閉じる)ボタンで終了すると、出力はされない。
File メニューからファイルの読み込みもできる
パイプなど標準入力を指定しないで起動した場合は、コンソールから入力するかしないですぐにCTRL+Z
選択は、
CTRL+マウスクリック
または、
SHIFT+マウスクリック
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
#light

open System
open System.IO  
open System.Windows.Forms

let form = new Form(Width= 400, Height = 300, Visible = true, Text = "HandGrep", Menu = new MainMenu())

// menu bar and menus 
let mFile = form.Menu.MenuItems.Add("&File")
let mHelp = form.Menu.MenuItems.Add("&Help")

// menu items 
let miOpen  = new MenuItem("&Open...")
let miQuit  = new MenuItem("&Quit")
let miAbout = new MenuItem("&About...")

mFile.MenuItems.Add(miOpen)  |> ignore
mFile.MenuItems.Add(miQuit)  |> ignore
mHelp.MenuItems.Add(miAbout) |> ignore

// ListBox
let listB = new ListBox(Dock=DockStyle.Fill)
listB.SelectionMode <- SelectionMode.MultiExtended

let in_ar = stdin.ReadToEnd().Split([|"\r\n"|],StringSplitOptions.RemoveEmptyEntries)
for s in in_ar do
    listB.Items.Add(s) |> ignore //drop index

form.Controls.Add(listB)

// filename state 
let mutable filename = ""
let SetFilename f  = filename <- f; form.Text <- "HandGrep - " ^ f

SetFilename "stdin"

// ReadFile dialog 
let ReadFile () =
    let d = new OpenFileDialog() 
    d.Filter <- "text files *.txt|*.txt|All files *.*|*.*";
    d.FilterIndex <- 2;
    if d.ShowDialog() = DialogResult.OK then
        let str  = new StreamReader(d.FileName)
        let text = str.ReadToEnd ()
        Some (d.FileName,text)
    else
        None


// Read in File 
let opLoadText _ = 
    match ReadFile () with
    | Some (file,text) -> 
        SetFilename file
        listB.Items.Clear()
        for s in text.Split([|"\r\n"|],StringSplitOptions.RemoveEmptyEntries) do
           listB.Items.Add(s) |> ignore //drop index
    | None -> ()


let opAbout _ = 
    MessageBox.Show("Selection StdIn","About HandGrep") |> ignore

let opExitForm _ =
    for item in listB.SelectedItems do
        stdout.WriteLine(string item)
    form.Close ()

// callbacks 
let _ = miOpen.Click.Add(opLoadText)
let _ = miQuit.Click.Add(opExitForm)
let _ = miAbout.Click.Add(opAbout)

[<STAThread()>]    
do Application.Run(form)

コンパイルオプション -g は、別に必要ないです。

WTLです。微妙にdecltypeを使っているので、Visual C++ 2010以上です、ごめんなさい。

複数行選択可能なリストボックスに表示。手抜きUIなのでメニューとかありません。ウィンドウの×を押して閉じたときに選択されていた項目を出力するという作りです。

Boost.Threadで読み取り用のスレッドを立てています。これにより、パイプの入力が時間の掛かる処理であっても、すぐにウィンドウが表示され、少しずつ項目が追加されるようになっています。

なお、パイプの入力がまだあるのにウィンドウを閉じた場合、自プロセスは入力が終わるまで待つ羽目になりますが、コード中のコメントにあるとおり、Vista以降だと同期IOのキャンセルができるため、すぐに自プロセスの終了が可能です。初めて使いました。

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
// どうせVC10でビルドしたプログラムはWindows 2000以上でしか実行できない。
#define WINVER 0x0500
#define _WIN32_WINNT 0x0500
#define _WIN32_IE 0x0500

#define _CRT_SECURE_NO_WARNINGS
#define _SCL_SECURE_NO_WARNINGS
#define _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES 1

#define WIN32_LEAN_AND_MEAN

#define _ATL_NO_AUTOMATIC_NAMESPACE
#define _WTL_NO_AUTOMATIC_NAMESPACE

#define BOOST_ALL_DYN_LINK

#include <tchar.h>

#include <iostream>
#include <string>
#include <functional>
#include <iterator>
#include <algorithm>
#include <memory>

#include <tchar.h>

#include <windows.h>

#include <atlbase.h>
#include <atlwin.h>
#include <atlapp.h>
#include <atlcrack.h>
#include <atlctrls.h>
#include <atlmisc.h>

#include <boost/thread.hpp>

#ifdef UNICODE
#    define tcout std::wcout
#    define tcin std::wcin
#else
#    define tcout std::cout
#    define tcin std::cin
#endif
typedef std::basic_string<TCHAR> tstring;

WTL::CAppModule _Module;

const int POINT_SIZE = 9;

class MainWindow : public ATL::CWindowImpl<MainWindow>
{
public:
    // ウィンドウクラスの登録
    DECLARE_WND_CLASS_EX(TEXT("HandGrep MainWindow"), 0, COLOR_3DFACE);
    // メッセージマップ
    BEGIN_MSG_MAP(MainWindow)
        MSG_WM_SIZE(OnSize)
        MSG_WM_CREATE(OnCreate)
        MSG_WM_DESTROY(OnDestroy)
    END_MSG_MAP()    
    // 読み取った文字列をリストボックスへ追加する。
    void AddLine(const tstring& s)
    {
        // 別スレッドへメッセージを送っているが、SendMessageなら同期されるので、問題ないはず。
        // エラー値が返ってくるかもしれないが、今回は無視する。
        if (listBox)
        {
            listBox.AddString(s.c_str());
        }
    }
private:
    void OnSize(UINT /*type*/, SIZE size)
    {
        listBox.MoveWindow(0, 0, size.cx, size.cy);
    }
    // ウィンドウ作成時の処理。
    BOOL OnCreate(CREATESTRUCT*)
    {
        // リストボックスの作成。
        HWND hwndListBox = listBox.Create(m_hWnd, 0, 0,
            LBS_MULTIPLESEL | WS_VSCROLL | WS_CHILD | WS_VISIBLE,
            WS_EX_CLIENTEDGE, IDC_LISTBOX);
        if (!hwndListBox)
        {
            return false;
        }
        // 等角フォントでの表示を試みる。
        WTL::CClientDC dc(m_hWnd);
        font.CreateFont(-MulDiv(POINT_SIZE, GetDeviceCaps(dc, LOGPIXELSY), 72),
            0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, DEFAULT_CHARSET,
            OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY,
            FIXED_PITCH | FF_MODERN, TEXT("MS ゴシック"));
        if (font)
        {
            listBox.SetFont(font);
        }
        return true;
    }
    // ウィンドウが閉じるときの処理。
    void OnDestroy()
    {
        // 選択されている要素だけを出力。
        int count = listBox.GetCount();
        std::vector<TCHAR> buf;
        for (int i = 0; i < count; ++i)
        {
            if (listBox.GetSel(i))
            {
                buf.resize(listBox.GetTextLen(i) + 1);
                listBox.GetText(i, &buf[0]);
                tcout << &buf[0] << TEXT('\n');
                buf.clear();
            }
        }
        tcout << std::flush;
        listBox = 0;
        PostQuitMessage(0);
    }
    WTL::CListBox listBox;
    WTL::CFont font;
    static const int IDC_LISTBOX = 1;
};
// 別スレッドで入力を読み取る。
void ReadThread(MainWindow& wnd)
{
    tstring s;
    while (!boost::this_thread::interruption_requested() && std::getline(tcin, s))
    {
        wnd.AddLine(s);
    }
}

int _tmain()
{
    std::locale l("");
    std::wcin.imbue(std::locale(""));
    std::wcout.imbue(std::locale(""));

    _Module.Init(0, GetModuleHandle(0));

    // ウィンドウの作成。
    MainWindow wnd;
    wnd.Create(NULL, ATL::CWindow::rcDefault,
        TEXT("HandGrep WTL"), WS_OVERLAPPEDWINDOW, WS_EX_APPWINDOW);
    boost::thread readThread(std::bind(ReadThread, std::ref(wnd)));

    wnd.ShowWindow(SW_SHOWDEFAULT);
    wnd.UpdateWindow();

    WTL::CMessageLoop msgLoop;
    _Module.AddMessageLoop(&msgLoop);
    int ret = msgLoop.Run();
    _Module.RemoveMessageLoop();

    // アプリケーションが終了しようとしていることを伝える。
    readThread.interrupt();

    // OSが対応していれば(Vista以降)、入力待ちを解除させる。
    typedef decltype(CancelSynchronousIo)* PCancelSynchronousIo;
    if (PCancelSynchronousIo pCancelSynchronousIo =
        reinterpret_cast<PCancelSynchronousIo>(
            GetProcAddress(GetModuleHandle(TEXT("kernel32")), "CancelSynchronousIo")))
    {
        pCancelSynchronousIo(readThread.native_handle());
    }
    _Module.Term();
    readThread.join();

    return ret;
}

> なお、パイプの入力がまだあるのにウィンドウを閉じた場合、自プロセスは入力が終わるまで待つ羽目になります

そこまで考えていませんでした。見事な対応も書いてあってすばらしいです。

swingで。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
#!/usr/bin/env groovy
import groovy.swing.*
import javax.swing.*

def swing = new SwingBuilder()
def frame = swing.frame(title:'Frame', defaultCloseOperation:JFrame.EXIT_ON_CLOSE, show:true, pack:true, id:"frame"){
    panel{
        vbox{
            list(listData:System.in.readLines() as Vector, id:"list", selectionMode:ListSelectionModel.MULTIPLE_INTERVAL_SELECTION){
            }
            button("出力!", actionPerformed:{ evt ->
                println swing.list.selectedValues.join("\n")
                System.exit(0)
            })
        }
    }
}
1
2
3
4
5
6
#!/bin/sh
file=$(mktemp /tmp/handgrep.XXXXXXXXXX)
trap "rm -f $file" EXIT
cat > $file
(${EDITOR:-vi} $file < /dev/tty > /dev/tty)
cat $file

swingにて。

HandGrepを初めて使ったのですが、便利そうなツールだと思いました。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import javax.swing.*;

public class HandGrep {
    public static void main( String[] args ) throws IOException {
        
        // フレームを生成
        
        final JFrame frame = new JFrame( "HandGrep" );
        frame.setDefaultCloseOperation( JFrame.DO_NOTHING_ON_CLOSE );
        
        // コンポーネントをフレームに配置
        frame.setLayout( new BorderLayout() );
        final JList list = new JList();
        JScrollPane scrollPane = new JScrollPane( list );
        frame.add( scrollPane, BorderLayout.CENTER );
        JButton button = new JButton( "完了" );
        frame.add( button, BorderLayout.SOUTH );
        
        // 初期処理(入力)
        
        DefaultListModel listModel = new DefaultListModel();

        BufferedReader reader = new BufferedReader( new InputStreamReader( System.in ) );
        String line;
        while ( ( line = reader.readLine() ) != null ) {
            listModel.addElement( line );
        }

        list.setModel( listModel);
        
        // 完了ボタン押下時の処理(出力&終了)
        
        button.addActionListener( new ActionListener() {
            public void actionPerformed( ActionEvent evt ) {
                for ( Object value : list.getSelectedValues() ) {
                    System.out.println( value );
                }
                
                frame.dispose();
            }
        } );
        
        // フレームを表示
        
        frame.pack();
        frame.show( true );
    }
}
C#で。標準入力とUIを別スレッドにしているので、追加入力可能です。
コマンドラインとUIの組み合わせって意外と新鮮だと思いました。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
using System;
using System.Windows.Forms;
using System.Threading;

namespace HandGrep {
    // 行選択ダイアログクラス
    class Dialog : Form {
        ListBox list;
        public ListBox List {
            get { return list; }
            private set { list = value; }
        }
        public Dialog() {
            this.Width = 300; this.Height = 200;
            this.Text = "選択して×ボタンを押してください。";
            this.List = new ListBox();
            this.List.Dock = DockStyle.Fill;
            this.List.SelectionMode = SelectionMode.MultiExtended;
            this.Controls.Add(this.List);
        }
        public void AddLine(string line) {
            this.List.Items.Add(line);
        }
    }
    // メインクラス
    class Program {
        static object objLock;                  // 排他オブジェクト
        static AutoResetEvent evDialogLoad;     // ダイアログ初期化イベント
        static AutoResetEvent evDialogClose;    // ダイアログ終了イベント
        static Dialog dlg;                      // ダイアログ
        delegate void MyDelegate();
 
        static void Main(string[] args) {
            objLock = new object();
            evDialogLoad = new AutoResetEvent(false);
            evDialogClose = new AutoResetEvent(false);

            // ダイアログ作成
            dlg = new Dialog();
            dlg.Load += new EventHandler(       // ダイアログ初期化イベントハンドラ登録
                delegate(object o, EventArgs e) {
                    evDialogLoad.Set();
                });
            // ダイアログを別スレッドで表示
            new MyDelegate(
                delegate() {
                    dlg.ShowDialog();
                }
            ).BeginInvoke(new AsyncCallback(OnDialogClose), null);
            evDialogLoad.WaitOne();             // ダイアログの初期化待ち
            // 標準入力ループ
            string line;
            while ((line = Console.ReadLine()) != null) {
                // 標準入力から1行読み込み、ダイアログに追加
                dlg.Invoke(new MyDelegate(
                    delegate() {
                        lock (objLock) {
                            if (dlg == null) return;
                            dlg.AddLine(line);
                        }
                    }
                ));
            }
            evDialogClose.WaitOne();            // ダイアログの終了待ち
        }
        // ダイアログクローズ後のコールバック
        static void OnDialogClose(IAsyncResult result) {
            lock (objLock) {
                // 選択行を標準出力に書き込む
                foreach (string line in dlg.List.SelectedItems) {
                    Console.WriteLine(line);
                }
                dlg = null;
            }
            evDialogClose.Set();
        }
    }
}

Rの標準機能だけで書いてみました。

標準入力を読ませたあと、excelのようなインターフェイスのデータエディタが起動するので、選択したい値の左にある"select"のカラムに0以外の値を記入してください。

1
2
3
4
hand.grep <- function(){
  df <- edit(data.frame(select=0, value=readLines()))
  as.character(df[(df[,1]!=0),2])
}

Squeak Smalltalk で。例によって標準入出力との連携は苦手なので、ファイル名を指定して内容を読み込み、一覧からクリックして選択した行群を完了ボタン後に文字列の配列として返す処理を書きました。

ちょっと風変わりな実装方法を試したところとしては、プラガブル MVC で使用するためのモデルとして、通常するように Model のサブクラスを新たに定義することはせず、その代わりに行内容と選択状態のキー・バリュー組を要素に持つ配列を用いたこと。そのために、ビュー・コントローラーとの連携のためのメソッドを、インスタンス特異的クラスを介し、モデルとして用いた配列オブジェクトにアドホックに追加している点です。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
| in lines file keyValues window linesList button results |
in := 'test.txt'.
lines := OrderedCollection new.
[   file := FileStream fileNamed: in.
    [file atEnd] whileFalse: [lines add: file nextLine].
] ensure: [file ifNotNil: [file close]].
keyValues := lines collect: [:each | each -> false].
keyValues assureUniClass.
keyValues class
    compile: 'keyList ^self collect: [:each | each key]';
    compile: 'stateAt: idx ^(self at: idx) value';
    compile: 'stateAt: idx put: boolean (self at: idx) value: boolean. self changed: nil'.
window := (SystemWindow labelled: '行をクリックして選択...') model: keyValues.
linesList := PluggableListMorphOfMany
    on: keyValues 
    list: #keyList
    primarySelection: nil
    changePrimarySelection: nil
    listSelection: #stateAt: 
    changeListSelection: #stateAt:put: 
    menu: nil.
button := (PluggableButtonMorph on: window getState: nil action: #closeBoxHit) label: '完了'.
window addMorph: linesList frame: (0.0 @ 0.0 corner: 1.0 @ 0.9).
window addMorph: button frame: (0.0 @ 0.9 corner: 1.0 @ 1.0).
ToolBuilder default runModal: (window openInWorld; yourself).
results := keyValues select: [:each | each value] thenCollect: [:each | each key].
keyValues class removeFromSystem.
^results asArray

Python+PyQt4(non-commacial版)で書いてみたのですが、ライセンスがGPLになってしまって、ここには載せられないことに気づいた(^^;

Ypsilon + GTK で書きました。リストウィジェットを使いたかったんですが、うまくいかなかったので、チェックボタン並べてます。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
(import (rnrs)
        (ypsilon gtk constants)
        (ypsilon gtk init)
        (ypsilon gtk main)
        (ypsilon gtk widget)
        (ypsilon gtk window)
        (ypsilon gtk scrolled)
        (ypsilon gtk container)
        (ypsilon gtk vpaned)
        (ypsilon gtk vbox)
        (ypsilon gtk box)
        (ypsilon gtk button)
        (ypsilon gtk check)
        (ypsilon gtk toggle)
        (ypsilon gobject signal)
        (ypsilon ffi))

(gtk_init (vector (length (command-line))) (apply vector (command-line)))

(let ((window (gtk_window_new GTK_WINDOW_TOPLEVEL))
        (scrolled-window (gtk_scrolled_window_new 0 0))
        (vpaned (gtk_vpaned_new))
        (button (gtk_button_new_with_label "OUTPUT"))
        (vbox (gtk_vbox_new 0 0))
        (destroy
            (signal-callback gboolean (GtkObject* gpointer)
                (lambda (obj data)
                    (gtk_main_quit))))
        (clicked
            (signal-callback gboolean (GtkButton* gpointer)
                (lambda (button vbox)
                    (let ((out (current-output-port)))
                        (gtk_container_foreach vbox
                            (lambda (button data)
                                (when (positive? (gtk_toggle_button_get_active button))
                                    (put-string out (gtk_button_get_label button))
                                    (newline out)))
                            0))))))

    (let ((in (current-input-port)))
        (let loop ((line (get-line in)))
            (unless (eof-object? line)
                (gtk_box_pack_start vbox (gtk_check_button_new_with_label line) 0 0 0)
                (loop (get-line in)))))

    (gtk_window_set_title window "HandGrep")
    (gtk_container_set_border_width window 10)
    (gtk_window_resize window 320 240)

    (g_signal_connect window "destroy" destroy 0)
    (g_signal_connect button "clicked" clicked vbox)
    (g_signal_connect_swapped button "clicked" gtk_widget_destroy window)

    (gtk_container_add vpaned button)
    (gtk_container_add vpaned vbox)
    (gtk_scrolled_window_add_with_viewport scrolled-window vpaned)
    (gtk_container_add window scrolled-window)
    (gtk_widget_show_all window)
    (gtk_main))
nattou_curry さんの #9045をscalaに移植してみました。
終了処理に自信なし・・・
たたき台なのでたたいて下さい。
環境はVistaでテスト。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
import swing._
import swing.event._
import scala.collection.mutable.ArrayBuffer
import scala.io.Source

object HandGrep extends SimpleGUIApplication {
  var args = Array[String]()
  override def main(args:Array[String]):Unit = {
    this.args = args
    super.main(args)
  }
  
  // data for list-view
  // read from stdin
  var lines = new ArrayBuffer[String]()
  lines ++= Source.fromInputStream(System.in).getLines
  //lines.foreach(print _) // for debug
  
  //create frame window
  def top=new MainFrame{
    title = "HandGrep"
    
    val list = new ListView[String](lines)
    val scrollPane = new ScrollPane(list)
    val button = new Button("Done")
    // add components 
    contents = new BorderPanel{
        add(scrollPane,BorderPanel.Position.Center)
        add(button    ,BorderPanel.Position.South)
      }
    listenTo(button)
    reactions +={
      // "Done" button clicked
      case ButtonClicked(b) =>{
        for{i<-list.selection.indices
            v=lines(i)} print(v)
        this.dispose
        System.exit(0)
      }
      
    }// end of reactions
  } // end of ctor of MainFrame
  //
}

言語がOtherになってしまった。すみません。 Sacalaです。

素直にwxPythonです。作り方は素直じゃないですが。この程度のものならOOP避けたいと思って。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
import wx

def gui_hand_grep(lines):
    app = wx.PySimpleApp()
    frame = wx.Frame(None, -1, "Hand Grep")
    lineslist = wx.ListBox(frame, -1, style=wx.LB_EXTENDED)
    uipanel = wx.Panel(frame, -1)
    okbutton = wx.Button(uipanel, -1, "OK")
    uipanel.Layout()
    sizer = wx.BoxSizer(wx.VERTICAL)
    frame.SetSizer(sizer)
    sizer.Add(lineslist, 1, wx.EXPAND | wx.ALL)
    sizer.Add(uipanel,   0, wx.EXPAND | wx.ALL)
    lineslist.Set(lines)
    sels = []
    def onOK(event):
        sels.extend(map(lambda pos: lines[pos], 
              lineslist.GetSelections()))
        app.ExitMainLoop()
    frame.Bind(wx.EVT_BUTTON, onOK, okbutton)
    frame.Show(True)
    app.SetTopWindow(frame)
    app.MainLoop()
    return sels

if __name__ == "__main__":
    lines = []
    eof = False
    while not eof:
        try:
            lines.append(raw_input())
        except EOFError:
            eof = True
    for sel in gui_hand_grep(lines):
        print sel

 scalaがまだの様なので。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
import    scala.swing.{BorderPanel, Button, ListView, FlowPanel, MainFrame, Menu, MenuBar, MenuItem, ScrollPane, SimpleGUIApplication}
import    scala.swing.event.{ActionEvent, ButtonClicked}

class HandGrepFrame(var lines:List[String]) extends MainFrame {
    
    title = "Hand Grep"
    
    menuBar = new MenuBar
    
    val    menu:Menu = new Menu("file")
    val    quitMenu:MenuItem = new MenuItem("quit")
    
    menu.contents += quitMenu
    menuBar.contents += menu
    
    val    list:ListView[String] = new ListView(lines)
    val    quit:Button = new Button("quit")
    
    contents = new BorderPanel {
        
        import BorderPanel.Position._
        
        layout(new ScrollPane(list)) = Center
        layout(new FlowPanel(FlowPanel.Alignment.Right) { contents += quit }) = South
    }
    
    listenTo(quitMenu, quit)
    reactions += {
        case ActionEvent(`quitMenu`) | ButtonClicked(`quit`) => quitHandler
    }
    
    preferredSize = (600, 480)
    pack
    
    def quitHandler:Unit = {
        list.selection.items.foreach(Console.println)
        System.exit(0)
    }
}

object HandGrep extends SimpleGUIApplication {
    val    lines:List[String] = readLines
    def readLines:List[String] = Console.in.ready match {
            case false => List[String]()
            case _ => Console.readLine :: readLines
        }
    def top = new HandGrepFrame(lines)
}
Ruby/Tkで。
行を選択してボタンを押すと標準出力へ出力します。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
require 'tk'

frame = TkFrame.new.pack(:fill => 'both')
scrollbar = TkScrollbar.new(frame).pack(:side => 'right', :fill => 'y')
listbox = TkListbox.new(frame).pack(:fill => 'both')
listbox.yscrollbar(scrollbar)

onButtonClick = proc { 
  begin
    print listbox.get(listbox.curselection); 
    exit; 
  rescue
    Tk.messageBox(:message => '行を選択してください')
  end
}

button = TkButton.new(:text => 'OK', :command => onButtonClick).pack(:side => 'bottom')
STDIN.read.each { |line| listbox.insert(:end, line.chomp) }

Tk.mainloop
VBScript版です。
dir | cscript Handgrep.vbs > list.txt
とかやると使えます。
GUIではなく、一行ずつ確認メッセージボックスが表示されて、OKを選択した行のみgrep対象となります。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
Set result = CreateObject("Scripting.Dictionary")

While WScript.StdIn.AtEndOfStream = False
    lineData = WScript.StdIn.ReadLine
    okOrCancel = msgbox("handgrep? " & lineData, 1)
    If okOrCancel = 1 Then
        result.Add lineData, ""
    End If
Wend

For Each resultLine In result.Keys
    WScript.StdOut.WriteLine resultLine
Next

Index

Feed

Other

Link

Pathtraq

loading...