質問
次のコマンドを入力して、特定の文字列を含む行の数を数えたとします。
me@machine $ command-producing-multi-line-output | grep -i "needle" | wc -l
では、"needle"
を他の単語にすばやく置き換えるにはどうすればよいでしょうか。
現在の非効率的なソリューション
今私は:
Up
を押して、最後のコマンドをロードします。"needle"
に到達するまでLeft
またはCtrl
+ Left
を押します。Backspace
またはCtrl
+ w
を押します。Enter
を押します。これはかなり非効率的です。
試行された機能しないソリューション
私は!!:sg/needle/new-needle
;のような履歴ショートカットを調査しようとしました。しかし、これにはいくつかの問題があります:
Up
を押して!!:sg/needle/new-needle
をコマンドラインに戻すことはできません。これを行うと、展開元が表示されます(元の問題に直接戻ります)。needle
とnew-needle
(つまり!!:sg/new-needle-from-before/yet-another-new-needle
)の両方を置き換える必要があります。!:4
や$4
(つまり!!:sg/!:4/new-needle
または!!:sg/$4/new-needle
)のようなものを使用する代わりに、needle
全体を入力して、時間やキーストロークを節約できます。針だった。!:^-3 "new-needle" !:5-$
のようなものも見つけましたが、これにも問題があります。
私がやりたいことを実行するには、超高速な方法が必要だと私は信じています。これに関するご意見やご提案をいただければ幸いです。
編集:
背景
ほんの少しの背景ですが、コマンドラインでOpenStackを頻繁に使用していて、パイプコマンドの長いコマンドチェーン内のいくつかの場所でパラメーターを置き換える必要があることがよくあります。
OpenStack環境の構成方法では、複数のエンジニアが任意の数のサーバーで単一のstack
ユーザーを共有し、複数の環境内に複数のクラスターがあります。したがって、.bashrc
または.profile
ファイル内で宣言された関数は実際には不可能です。
必要な設定がまったくないか、最小限で済み、すぐに使用できるポータブルなものを期待しています。それ以外の場合は、シェルの外で完全にソリューションを使用する必要があるかもしれません(AutoHotKey/Keyboard Maestro/AutoKeyなどのクリップボードの交換など)。
私は同様の状況に遭遇し、それが有用なパターンである場合に備えて、ここに私の解決策を提示しました。
インタラクティブに置き換えるのが面倒な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
このコマンドラインの将来が「今日」を超えていると思われる場合は、関数またはスクリプトに記述します。
それはexactlyhistory Expansion の意味です:
$ command-producing-multi-line-output | grep -i "needle" | wc -l
...
$ ^needle^nipple
command-producing-multi-line-output | grep -i "nipple" | wc -l
...
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はksh
はfc -s
のデフォルトエイリアス、ksh93
はhist -s
のデフォルトエイリアスです。等.
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 needle
、q haystack
、q something
を使用できます。これは、現在受け入れられている回答のwhile
ソリューションよりも優先されます。これは、検索/カウントの間に他のコマンドを許可するためです。
この特定のケースでは、私は実際に定義します
q(){ command-producing-multi-line-output | grep -i "$@";}
私はおそらく実際に一致する行をある段階で確認したいので、q needle | wc -l
以上のq -c needle
を使用してカウントし、q needle
を使用して行を表示できます。
関数定義はbash履歴に保存されるため、将来のセッションで必要になった場合は、通常、定義を再ロードできます。
概要: 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
私はこのために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}"
このために作成された適切なエディターを開きます。デフォルトでは、これを行うことができます Ctrl-xCtrl-e、ただしvi編集モードを有効にしている場合(一方通行はset -o vi
)、あなたも使用できます Escv。
そこに移動したら、エディターの置換コマンドを使用します。 vi(m)では、たとえば、
:%substitute/needle/haystack/g