なんかで、mv
したのを元に戻したいとき
なんかで、cp
したのを元に戻したいとき
コマンドを懇切丁寧に打ち直すのは避けたいものだ。
そんな時は、コマンド履歴。つっても、 history
やら fc
やらのお話では無い。(関係はしてるけど)
キーワードは、 bash
の「イベント指示子」と「単語指示子」とその「修飾子」。
もちろん、 zsh
でも使える。
ファイル対ファイル
前提
- コマンドに対するオプションを使ってない、ファイル対ファイルの単純なケースを想定
- 対象コマンドでは、ブレース展開を使ってない(履歴に残ってない)事。
- ブレース展開を使ってた場合については後述
$ touch foo
$ mv foo foo.bak
なんらかの理由で .bak を元に戻したい時
直近
対象 mv
以降にコマンドを打っていないケースの場合。
mv
に直近のコマンドの最後の引数 !$
と二番目のコマンド文字列 !:1
を与える。
$ mv !$ !:1
第一引数 !^
を与える。
$ mv !$ !^
もしくは、多くのケースでは、
mv
に直近のコマンドの最後の引数 !$
と、それの拡張子を除いた単語 !$:r
を与える。
$ mv !$ !$:r
拡張子ではなく、foo~
の様にしていた場合は、
$ mv foo foo~
$ mv !$ !$:s/~//
- 早合点しがちだが、
s///
の変換前部分も 正規表現表記ではない。単なる文字列。(変換後部分は言うまでもないが)
実際に使うのは
殆どの場合は、別の作業をした後に実行するので、
コマンド履歴の番号でアクセスするか、コマンド文字列参照によってアクセスする事になる。
$ history
(略)
140 mv foo foo.bak
(略)
$ mv !140$ !140:1
$ mv !-2$ !-2:1
2回前だった場合ね
$ mv !m:$ !m:1
more
とか他の m で始まるコマンドを間に挟んでたら、!m
を !mv
にすればいい。
- 文字列の時は、
!m$
はエラーになる。同様に!m^
も。
ブレース展開を使ってた場合
$ mv foo{,.bak}
展開してない状態で履歴に残ってたら。
直前なら、
^,.bak^.bak,
そうでないなら、
!mv:s/.bak,/,.bak/
- こちらも、
s///
の変換前部分は 正規表現表記ではない。単なる文字列。
大事な事なので二度言いました。 - このケース。
zsh
では、 文字列記載後にタブを打つ事で、展開させる事が可能なので、展開させて制約を除くほうが都合が良い。
ここまで押えれば、
後は、ケースバイケース。工夫次第で、色々活用出来る。
例えば、ある拡張子を持つファイルを、ごそっと移動した以下の様な場合に、元に戻したくなったとする。
$ touch foo.pl bar.pl buz
$ mkdir foo
$ mv *.pl foo
移動先に同一拡張子のものが無いと言う保証があるなら、
$ mv !$/!:1 .
で復元が出来る。