web-dev-qa-db-ja.com

パイプコマンドチェーンのパラメーターをすばやく置き換える方法

質問

次のコマンドを入力して、特定の文字列を含む行の数を数えたとします。

me@machine $ command-producing-multi-line-output | grep -i "needle" | wc -l

では、"needle"を他の単語にすばやく置き換えるにはどうすればよいでしょうか。


現在の非効率的なソリューション

今私は:

  1. キーボードのUpを押して、最後のコマンドをロードします。
  2. "needle"に到達するまでLeftまたはCtrl + Leftを押します。
  3. Wordを削除するには、BackspaceまたはCtrl + wを押します。
  4. 新しい単語を入力するか貼り付けます。
  5. Enterを押します。

これはかなり非効率的です。


試行された機能しないソリューション

私は!!:sg/needle/new-needle;のような履歴ショートカットを調査しようとしました。しかし、これにはいくつかの問題があります:

  1. Upを押して!!:sg/needle/new-needleをコマンドラインに戻すことはできません。これを行うと、展開元が表示されます(元の問題に直接戻ります)。
  2. これをさらに別の新しい針で繰り返すには、needlenew-needle(つまり!!:sg/new-needle-from-before/yet-another-new-needle)の両方を置き換える必要があります。
  3. !:4$4(つまり!!:sg/!:4/new-needleまたは!!:sg/$4/new-needle)のようなものを使用する代わりに、needle全体を入力して、時間やキーストロークを節約できます。針だった。

!:^-3 "new-needle" !:5-$のようなものも見つけましたが、これにも問題があります。

  1. 履歴が拡大するため、すぐに再利用することはできません。
  2. 展開されなかったとしても、コマンドチェーンの途中でWordを置き換える必要があるという元の問題に遭遇します。

私がやりたいことを実行するには、超高速な方法が必要だと私は信じています。これに関するご意見やご提案をいただければ幸いです。


編集:

背景

ほんの少しの背景ですが、コマンドラインでOpenStackを頻繁に使用していて、パイプコマンドの長いコマンドチェーン内のいくつかの場所でパラメーターを置き換える必要があることがよくあります。

OpenStack環境の構成方法では、複数のエンジニアが任意の数のサーバーで単一のstackユーザーを共有し、複数の環境内に複数のクラスターがあります。したがって、.bashrcまたは.profileファイル内で宣言された関数は実際には不可能です。

必要な設定がまったくないか、最小限で済み、すぐに使用できるポータブルなものを期待しています。それ以外の場合は、シェルの外で完全にソリューションを使用する必要があるかもしれません(AutoHotKey/Keyboard Maestro/AutoKeyなどのクリップボードの交換など)。

11
Jeff Reeves

私は同様の状況に遭遇し、それが有用なパターンである場合に備えて、ここに私の解決策を提示しました。

インタラクティブに置き換えるのが面倒な1つのデータを繰り返し変更していることに気付いたら、停止して少しのwhileループを作成します。

$ command-producing-multi-line-output | grep -i "needle" | wc -l
0
$ command-producing-multi-line-output | grep -i "haystack" | wc -l
0
$ while read needle; do

Up-Arrow 前のcommand-producing-multi-line-output行と置換"haystack""$needle"

command-producing-multi-line-output | grep -i "$needle" | wc -l; done
something
0
something else
0
gold
1

(で終わる Control+D

または、少し手の込んだバリエーション:

$ while read needle; do
printf 'For: %s\n' "$needle"
command-producing-multi-line-output | grep -i "$needle" | wc -l; done

このコマンドラインの将来が「今日」を超えていると思われる場合は、関数またはスクリプトに記述します。

10
Jeff Schaller

それはexactlyhistory Expansion の意味です:

$ command-producing-multi-line-output | grep -i "needle" | wc -l
...
$ ^needle^nipple
command-producing-multi-line-output | grep -i "nipple" | wc -l
...
11
mosvy

bashの便利なエイリアスは

alias r='fc -s'

rコマンドは、デフォルトで他のシェルによく見られます1、および履歴内の最新のコマンドを繰り返します。 bashマニュアルでは、これを定義するのに便利なエイリアスとして参照しています:

[...]  A useful alias to use with this is ``r="fc -s"'',
so that typing ``r cc'' runs the last command beginning with
``cc'' and typing ``r'' re-executes the last command.

また、最後のコマンドのテキストで置換を行うこともできます。

ここでコマンドを実行し、上記のエイリアスを使用してWord needleをWord haystackに置き換えます。

$ command-producing-multi-line-output | grep -i "needle" | wc -l
bash: command-producing-multi-line-output: command not found
       0
$ r needle=haystack
command-producing-multi-line-output | grep -i "haystack" | wc -l
bash: command-producing-multi-line-output: command not found
       0

コマンドラインでr needle=haystackを使用すると、シェルは実行するコマンドを出力し、すぐに実行します。ご覧のとおり、Wordの代わりにもなります。

エラーは明らかにcommand-producing-multi-line-outputコマンドがないために発生しますが、この演習ではそれは重要ではありません。


fcコマンドは履歴に保存されませんが、次のようなシェル関数として作成することで保存できます。

fc() {
    command fc "$@"
    history -s fc "$@"   # append the given fc command to history
}

あなたはそれから

$ command-producing-multi-line-output | grep -i "needle" | wc -l
bash: command-producing-multi-line-output: command not found
       0

commで始まる最新のコマンドを再実行し、r needle=haystack commを使用してneedleを置き換えます。

$ r needle=haystack comm
command-producing-multi-line-output | grep -i "haystack" | wc -l
bash: command-producing-multi-line-output: command not found
       0

r haystack=beeswaxを使用して、最新のコマンドを再実行しますが、haystackを置き換えます。

$ r haystack=beeswax
fc -s needle=beeswax comm
command-producing-multi-line-output | grep -i "beeswax" | wc -l
bash: command-producing-multi-line-output: command not found
       0

最後の行でfcに対して行われる二重呼び出しに注意してください。最初にエイリアスrを使用し、次に関数fcを使用しています。

明らかに、fcコマンドを履歴に保存すると、誤ってfc -sを再帰的に呼び出す危険性があります。


1zshは組み込みコマンド、OpenBSDはkshfc -sのデフォルトエイリアス、ksh93hist -sのデフォルトエイリアスです。等.

8
Kusalananda

OPは、.bashrcで宣言された関数は実用的ではないと言いますが、対話的に宣言するのを止めるものは何もありません。これは現在のセッションのためのものなので、1文字の名前が適しています。 q

で始まります

$ command-producing-multi-line-output | grep -i "haystack" | wc -l

押す Up;} 関数を終了するには、haystack$1に編集します。 Control+aq(){Space 取得するため

q(){ command-producing-multi-line-output | grep -i "$1" | wc -l;}

次に、q needleq haystackq somethingを使用できます。これは、現在受け入れられている回答のwhileソリューションよりも優先されます。これは、検索/カウントの間に他のコマンドを許可するためです。

この特定のケースでは、私は実際に定義します

q(){ command-producing-multi-line-output | grep -i "$@";}

私はおそらく実際に一致する行をある段階で確認したいので、q needle | wc -l以上のq -c needleを使用してカウントし、q needleを使用して行を表示できます。

関数定義はbash履歴に保存されるため、将来のセッションで必要になった場合は、通常、定義を再ロードできます。

5
icarus

概要: Ctrl+R nee Alt+D haystack Enter

押す Ctrl+R 逆インクリメンタル検索を開始し、目的のコマンドラインの目的の部分が表示されるまで(置き換える必要はありません)、置き換えるテキスト(またはそれに非常に近いテキスト)を数文字入力します。前のコマンドラインになる)。押す Ctrl+R 前の出現を検索します。押す Ctrl+S 行きすぎた場合は、先に進みます。押す Backspace 文字を誤って入力した場合。

目的の場所に到達したら、次のようなキーを使用できます Delete、 Alt+D または Alt+Backspace カーソルの周りのテキストの削除を開始する、または単に Escape 到達したポイントでインクリメンタル検索を終了します。

押す Enter コマンドラインの編集が終了したときのみ。ご了承ください Enter 増分検索中は、現在のコマンドラインをそのまま実行するという通常の意味があります。検索モードを終了するだけではありません( Escape 検索モードを終了するだけです)。

これらの状況では、次のようにパラメーターの環境変数をよく使用します。

ARG1=needle; command-producing-multi-line-output | grep -i "${ARG1}" | wc -l

最初の割り当ては、その後のコマンドで使用できる環境変数を設定します。これは、必要に応じて変更できるパラメーターとして機能します。これにより、このシェルの存続期間に環境変数が設定されますが、これで問題ないことをすばやく特定のコマンドで確認できました。変数の展開には通常の規則が適用されます。たとえば、単一引用符 '$ {ARG1}'は変数を展開しません。これに関する一般的な情報(ここに1つあります) https://www.gnu.org/software/bash/manual/html_node/Quoting.html

0
Paul

私はこのためにfzfを使用しています。

fzfのようなものをインストールするつもりで、出力が通常は画面よりも小さい場合は、次のことを試してください。

echo | fzf -q 'shuf < /usr/share/dict/words | grep needle | head' --preview-window=up:99% --preview="eval {q}"

出力がポップアップしたら、Wordの「needle」の最後にカーソルを合わせ、Ctrl-Wを押してhaystackと入力します。次に、もう一度Ctrl-Wを押して、他の単語を入力します。等々。

ただし、システムを変更するコマンドについてはこれをお勧めしません:-)あなたはfzfのプレビュー機能を使用してコマンドを実行しており、fzfは何かが変更されるとすぐにそれを実行しようとします。たとえば、Ctrl-Wを押すと、grepに使用法のメッセージが表示されます。これは、置換後のWordの最初の文字を入力するまで、引数がないためです。

私はこれを頻繁に使用するので、tryというスクリプトがあります。これは基本的には次のとおりです。

#!/bin/bash

export FZF_DEFAULT_COMMAND=echo
fzf -q "$*" --preview-window=up:99% --preview="eval {q}"
0
sitaram

このために作成された適切なエディターを開きます。デフォルトでは、これを行うことができます Ctrl-xCtrl-e、ただしvi編集モードを有効にしている場合(一方通行はset -o vi)、あなたも使用できます Escv

そこに移動したら、エディターの置換コマンドを使用します。 vi(m)では、たとえば、

:%substitute/needle/haystack/g
0
D. Ben Knoble