2017年6月19日月曜日

peco/fzfは外部コマンド実行用コマンドを作っておくと便利

前回に続きpecofzfネタです。 peco/fzfはとても便利なのですが、コマンドを実行するのは少し面倒だったりします。 具体的には、pecoでファイル一覧を表示、ファイルを選択してdirディレクトリにコピーする場合、以下のコマンドを打ちます。
cp `ls -a -p | peco` dir              # 方法1
ls -a -p | peco | xargs -J% cp % dir  # 方法2
「`」だったり細かなオプションが問題で、割と入力しにくいんですよね。 またxargsのオプション覚えるのも面倒だし、事前に何を実行するかわからない事も多い。 そこで以下のスクリプトをxコマンドとして登録してみる事にしました。
#!/usr/bin/env ruby

require 'readline'  # gem install rb-readline

# 入力を置換したいキーワードを登録
keyword = '@'


commands = `bash -ic "compgen -ac"`.split("\n")
if ARGV[0]
  dir = ARGV[0]
else
  dir = '.'
end

# list = `ls -a -p "#{dir}" | peco`
# list = `ls --color -a -p "#{dir}" | fzf --ansi -m`
list = `ls --color -a -p "#{dir}" | fzf --ansi -m --preview 'ls -C #{dir} --color=auto'`
puts list.split("\n").take(10).join(', ')

# Linuxコマンド補完をできるように
# https://marmooo.blogspot.jp/2017/06/linuxruby.html
Readline.completion_proc = proc {|s|
  last_command = Readline.line_buffer.split(/\s*[|$]\s*/)[-1]
  if last_command =~ /^.*\s+/
    Dir.glob(dir).grep( /^#{Regexp.escape(s)}/ )
  else
    commands.grep( /^#{Regexp.escape(s)}/ )
  end
}
cmd = Readline.readline("Execute: ")

exit if cmd.empty?
cmd = "#{cmd.strip} #{keyword}" if !cmd.include?(keyword)
cmd.gsub!(keyword, list.gsub("\n", ' '))
system("bash -ic '#{cmd}'")
xコマンドを実行すると、peco/fzfで何らかの処理したいファイルを選択した後、入力画面が出てきます。 そこで処理したいファイル郡@に対して任意の処理を指定する事ができます。 最初の例を実行する場合は以下のように入力すればOKです。 dir部分の入力にはシェルと同様の補完が効いています。
cp @ dir
備考ですが、置換キーワードに「@」を登録したのはファイル名に使われにくく入力しやすいからです。 また"bash -ic '#{cmd}'"という形式で実行しているのは、~/.bashrcの設定を引き継ぎながら実行するためです。 この設定がないと、例えばlsを実行した時などに--color=autoの設定が反映されません。

このxコマンドは前回紹介したcコマンドと組み合わせる事もできます。以下のようにcコマンドを実行後にxコマンドを起動するようにすれば、ディレクトリを移動した後にすかさずxコマンドでフィルタリングできます。ただ少しやり過ぎかなとも思うので、私はlsにしています。
function c { cd "`cdp $1`"; ls; }  # from
function c { cd "`cdp $1`"; x; }   # to
xコマンドを登録して、大量ファイルの処理が少し楽になりました。

0 件のコメント: