手作業Grep
Posted feedbacks - Flatten
Nested HiddenF# で、作ってみました。 (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 );
}
}
|
コマンドラインと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になってしまって、ここには載せられないことに気づいた(^^;
> なお、パイプの入力がまだあるのにウィンドウを閉じた場合、自プロセスは入力が終わるまで待つ羽目になります
そこまで考えていませんでした。見事な対応も書いてあってすばらしいです。
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
|






nobeer #9015() Rating5/5=1.00
標準入力を読み込んで、行選択のUIをだし、選択されたものだけを標準出力にだしてください。 標準出力に出力するタイミングは選択終了をユーザーが報告したときです。(完了ボタンを想定してください)
UIライブラリは何をつかってもかまいません。 例えばncursesのようなコンソール上でのUIでもかまいませんし、GtkのようなGUIライブラリでもかまいません。
想定される使い方としては、以下のような感じです。
ps aux | handgrep | xargs kill -9
プロセスの一覧を表示、UI上で選択したものをkill
[ reply ]