web-dev-qa-db-ja.com

stdoutに転送する前に手動で行を選択/選択解除

grep interactivelyへの方法はありますか?これは、パイプを追加して処理したいところからたくさんの行があり、必要な行を手動で指定するオプションがあることを意味しますか?

この例を考えてみましょう:

#Name   Food    Music
Adam    Cake    Rock
Bert    Fruit   Folk
Caesar  Cake    Rock
Doris   Cake    Folk
Emil    Fruit   Rock
Francis Fruit   Folk
Gertrud Cake    Rock
...

このファイルを取得し、次のような行を使用してフィルタリングできます

cat people.txt | grep -v "^#" | grep "^.*Fruit.*Folk"

...すべての人にベジフォークパーティーに招待してもらいます。これをさらに自動化すると:

cat people.txt | grep -v "^#" | grep "^.*Fruit.*Folk" | ??? | peopleInviterScript

...いくつか食べたい???パイプで、招待状が送信される前にユーザーを選択/選択解除するオプションを提供します。

私が知らないbash/zshにはすでにそのようなツールがありますか?

17
Bowi

私はvipeアプローチが好きですが、さらにクールな方法を見つけました: fzf

cat people.txt | grep -v "^#" | grep "^.*Fruit.*Folk" | fzf -m | cat

...キーボードで項目を検索して切り替えることができる素敵なリストを提供し、終了すると完全に消えます。

21
Bowi

moreutilsにはvipeがあり、パイプラインの一部として通常のテキストエディター(viなど)を実行するだけです。削除しない行はstdoutに書き戻されます。 (ただし、一般に、一時ファイルにリダイレクトしてそのファイルを編集しても同じ結果が得られます。)

18
user1686

gvim(およびvim)を使用することもできます。挿入gvim /dev/stdinをパイプに入れ、:wq! /dev/stdout編集が終了したとき。

次のようにgvimを呼び出すと、より自然にZZを記述して閉じることができます。

gvim +'nmap ZZ :wq!<cr> | r /dev/stdin | 1d | file /dev/stdout'

そのエイリアスまたは関数を作成できます。

gvimp() {
  gvim +'
    nmap ZZ :wq!<cr>
    r /dev/stdin
    1d
    file /dev/stdout
  '
}

以下は、4〜7行目を削除し、通常モードでZZを実行して終了した例です。

$ seq 1 10 | gvimp | sed -r 's/^|$/=/g'
=1=
=2=
=3=
=8=
=9=
=10=

編集:通常のvimは、キーボード入力にstdinを使用し、ユーザーインターフェイスの描画にstdoutを使用するため、少しトリッキーです。ただし、追加のプロセスを追加することで引き続き使用できます。 vimのstd *をターミナルにリダイレクトし、親プロセスのstd *をデータパイプに使用します。

vimp() {
  bash -c '
    terminal="/dev/$(ps -o tty= $$)"
    tmp_out="$(mktemp)"
    trap "rm \$tmp_out" EXIT
    vim <(cat) < "$terminal" &> "$terminal" +"
      file $tmp_out
      set noreadonly
      nmap ZZ :wq!<cr>
    "
    cat "$tmp_out"
  '
}

そうしないと、パイプ出力がvimのユーザーインターフェイスと混ざり、vimの終了時に一時ファイルが消える可能性があるため、一時ファイルが必要です。

5
JoL