😊
シェルで途中まで入力したコマンドを一時保存して後から実行する小技
シェルで長ったらしいコマンドを入力している途中に「先に別のコマンドを実行しておくべきだった」と気付いたことはないでしょうか。とくにワンライナースクリプトLOVEなみなさんは、こういうことがよく発生するのではないでしょうか。こういうときに泣く泣く入力中の文字列を消してから別のコマンドを実行して、いったん削除したコマンドを打ち直しているでしょうか。それとも、文字列をカットしてから後から貼り付けしているでしょうか。
こういうときに入力中だったコマンドを一時保存して後から実行する小技を紹介します。どこに一時保存するかというと、それはシェルの履歴です。具体的には「入力中だったコマンドの先頭に移動して「#」を入力してからenterを押す、他のことをした後に履歴をたどって"#"を消して実行」というものです。以下に例を示します。
-
awk '{<長大なワンライナー>}' <input.data > output.data
まで入力したところで「しまった、input.dataをまだ生成していない!」と気づく - 行頭に移動して「#」を入力してenterを押す。コメントとして扱われるので何も実行されないが、履歴には(「#」付きのものが)残る。
- input.dataを生成するコマンドを実行する。たとえば
make input.data
など。 - 「↑」などで履歴をたどる。
#awk '{<長大なワンライナー>}' <input.data > output.data
が見つかる。 - 行頭に移動して「#」を削除してenterを押す。
-
input.data
があるので無事成功。
別にシェルやらターミナルやらの隠された機能を使うわけではない、知ってしまえば大したことないネタですが、身の回りに知らない人がけっこういたので、ここでも共有しました。おわり。
Discussion
こんなに簡単な方法があったとは!
Ctrl+u, Ctrl+y でも同様のことがもっと簡単にできる気がするのですが、こちらの方法を使うメリットは何でしょうか?
2回以上Ctrl+uをすると、n-1回目の内容が消えませんか
あいやさんがおっしゃるとおり、同様のことを複数回やったときに全て履歴に残せるのがメリットです。C-u C-yだと最新のものしか残せないです。
なるほど、確かに仰る通りですね。2回以上Ctrl+uしたときに「あ〜さっき切り取ったやつ復元したい…」となったときの気持ちを思い出しました。
Zsh だと Ctrl-y → ESC-y → ESC-y ... で戻れるみたいですね。
Ctrl-u を yank できるのを初めて知りました。 🙏
コレよくやるけど、前側のコマンドを追加修正して実行してを何度か繰り返してるうちに、# の存在を忘れたまま # の後ろのコマンド部分を直し始めてしまい、当然#の後ろを直しても何も変わらんのでうまく動作しないと悩むフェーズに入りがち…。
ためになる tips を共有してくださりありがとうございます!
bash を想定されている記事かと思いますが、zsh では少し挙動が異なるので共有します。
zsh ではデフォルトで 対話モードでは
#
がコメントになりません!そのため、何も設定していない場合:
のようなエラーになります。
bash と同じく対話モードでも
#
以降をコメントにしたい場合は、.zshrc
に次の 1 行を追加する必要があります。エラーになっても履歴を残すという目的は達成しているのでいいような。
へえ~、そんなオプションが…!
僕はそれを知らなかったので、
:
コマンドを使っていました 🙋♂️:
がコマンドとして定義されていること初めて知りました…!!こちらだとPOSIX準拠のシェルで動作が統一されていそうなので、本記事のテーマの最適解な気がしてきました(展開の副作用は反映されるようですが)
zshならESC q (M-q)のpush-lineを使ってほしい。
同じことechoでやってましたが使えるなら#のほうがベターそうですね。参考になりました
便利なテクをありがとうございます。
カーソルを0文字目に戻す操作を、素の状態で試してみたら
bashでは
Ctrl + ←
、Fn + ←
、Alt + ←
で行けました。zshだと
Ctrl + ←
、Fn + ←
だけ行けました。Fnのこんな機能は知りませんでした。
ctrl+a ではだめですか?
Ctrl + a
でどっちのシェルも行けました。左手だけで操作できて便利なのですね。
あと訂正で、
Ctrl + a
と同じ挙動はCtrl + ←
だけでほかは半角スペース区切りの先頭でした。
ですよね。ちなみにctrl+eで行末です。
ctrl+e ctrl+u と連続で打つと行が全て消えて便利です。
今までは、ctrl + cで一度中断した後に、入力途中のコマンドをコピー&貼り付けしてから入力し直していたので、
とても参考になりました。
先頭に#を入れる or 先頭に#ある場合は除く、動作をキーバインドで設定すると良さそうと思ったので、zshの例ですが、zsh widgetを考えてみました。