iTranslated by AI

The content below is an AI-generated translation. This is an experimental feature, and may contain errors. View original article
😊

Shell Trick: Saving and Executing Partially Entered Commands Later

に公開18

Have you ever realized while typing a long, tedious command in the shell that you should have executed another command first? This probably happens quite often, especially for those of you who love one-liner scripts. In such situations, do you reluctantly delete the text you were typing, run the other command, and then retype the original one? Or do you cut the string and paste it later?

Here is a small trick to temporarily save the command you are typing and execute it later. Where do you save it? In your shell history. Specifically, the method is: "move to the beginning of the command, type '#', and press Enter; then, after finishing the other task, find it in your history, remove the '#', and execute it." Here is an example:

  1. You type as far as awk '{<long one-liner>}' <input.data > output.data and realize, "Wait, I haven't generated input.data yet!"
  2. Move to the beginning of the line, type "#", and press Enter. Since it's treated as a comment, nothing is executed, but it remains in your history (with the "#").
  3. Run the command to generate input.data. For example, make input.data.
  4. Scroll through your history using the "↑" key or similar. You will find #awk '{<long one-liner>}' <input.data > output.data.
  5. Move to the beginning of the line, delete the "#", and press Enter.
  6. It succeeds because input.data now exists.

It's not like you're using a hidden feature of the shell or terminal; it's a simple trick once you know it. However, since quite a few people around me didn't know it, I decided to share it here. That's all.

Discussion

-p Hk-p Hk

こんなに簡単な方法があったとは!

ilovegaloisilovegalois

Ctrl+u, Ctrl+y でも同様のことがもっと簡単にできる気がするのですが、こちらの方法を使うメリットは何でしょうか?

satsat

あいやさんがおっしゃるとおり、同様のことを複数回やったときに全て履歴に残せるのがメリットです。C-u C-yだと最新のものしか残せないです。

ilovegaloisilovegalois

なるほど、確かに仰る通りですね。2回以上Ctrl+uしたときに「あ〜さっき切り取ったやつ復元したい…」となったときの気持ちを思い出しました。

kosekikoseki

Zsh だと Ctrl-y → ESC-y → ESC-y ... で戻れるみたいですね。
Ctrl-u を yank できるのを初めて知りました。 🙏

Yoshiaki KawazuYoshiaki Kawazu

コレよくやるけど、前側のコマンドを追加修正して実行してを何度か繰り返してるうちに、# の存在を忘れたまま # の後ろのコマンド部分を直し始めてしまい、当然#の後ろを直しても何も変わらんのでうまく動作しないと悩むフェーズに入りがち…。

tomoritomori

ためになる tips を共有してくださりありがとうございます!
bash を想定されている記事かと思いますが、zsh では少し挙動が異なるので共有します。


zsh ではデフォルトで 対話モードでは # がコメントになりません
そのため、何も設定していない場合:

$ # echo hello
zsh: command not found: #

のようなエラーになります。

bash と同じく対話モードでも # 以降をコメントにしたい場合は、.zshrc に次の 1 行を追加する必要があります。

setopt INTERACTIVE_COMMENTS
TakumibooTakumiboo

エラーになっても履歴を残すという目的は達成しているのでいいような。

あいや - aiya000あいや - aiya000

へえ~、そんなオプションが…!
僕はそれを知らなかったので、:コマンドを使っていました 🙋‍♂️

$ # cp ~/Repository/vket-boilerplate-nuxt/develop/{.editorconfig,.gitattributes,.lintstagedrc.json,.prettierrc} .
zsh: command not found: #

$ : cp ~/Repository/vket-boilerplate-nuxt/develop/{.editorconfig,.gitattributes,.lintstagedrc.json,.prettierrc} .
(no output)
クロパンダクロパンダ

同じことechoでやってましたが使えるなら#のほうがベターそうですね。参考になりました

kako-junkako-jun

便利なテクをありがとうございます。

カーソルを0文字目に戻す操作を、素の状態で試してみたら
bashでは Ctrl + ←Fn + ←Alt + ← で行けました。
zshだと Ctrl + ←Fn + ← だけ行けました。

Fnのこんな機能は知りませんでした。

kako-junkako-jun

Ctrl + a でどっちのシェルも行けました。
左手だけで操作できて便利なのですね。

あと訂正で、Ctrl + a と同じ挙動は Ctrl + ← だけで
ほかは半角スペース区切りの先頭でした。

khkh

ですよね。ちなみにctrl+eで行末です。
ctrl+e ctrl+u と連続で打つと行が全て消えて便利です。

ryo.ryo.

今までは、ctrl + cで一度中断した後に、入力途中のコマンドをコピー&貼り付けしてから入力し直していたので、
とても参考になりました。

先頭に#を入れる or 先頭に#ある場合は除く、動作をキーバインドで設定すると良さそうと思ったので、zshの例ですが、zsh widgetを考えてみました。

_insert_comment() {
  if [[ $BUFFER =~ ^[[:space:]]*# ]]; then
      # 既にコメントアウトされている場合は解除
      BUFFER=${BUFFER#"${BUFFER%%[![:space:]]*}"}  # 前方の空白を削除
      BUFFER=${BUFFER#\#}  # #を削除
      BUFFER=${BUFFER#[[:space:]]}  # #の後の空白を削除
  else
      # コメントアウトされていない場合は追加
      BUFFER="# $BUFFER"
  fi
  zle redisplay
}
zle -N _insert_comment
bindkey '^Q' _insert_comment # ctrl + qで先頭に#追加 or 削除