【bash】ヒストリ機能での`!#`の使い途


前置き

以前こんな記事を書きました
【bash】!-n$ができるってそれもっと早く教えてよ! - Qiita

bash(以外でもあると思いますけど)のヒストリ機能では、
!-3で3回前のコマンド実行、!$で直前のコマンド実行の最後の引数、!-2$で2回前のコマンド実行の最後の引数、などが参照できます。

その辺りを調べるために、man bashHISTORY EXPANSION(履歴の展開)セクションを読んでいたらこんなものもありました。

!# The entire command line typed so far.

日本語版(Man page of BASH)

!# これまでに打ち込んだコマンドライン全体。

つまり以下のような動きをします

$ echo hoge fuga !#
echo hoge fuga echo hoge fuga
hoge fuga echo hoge fuga

?????

一旦なにに使えるんだ??

と最初に読んだときは思いました。

が、最近使いどころがわかってきたので紹介します

本題

!# これまでに打ち込んだコマンドライン全体。」というのは、見方を変えると、
!!!-1のエイリアスだとすると、!#!-0のエイリアスだと見ることができます。
(実際には!-0なんて使えないですけど。)

つまり、!#もイベント指示子なので、単語指示子と組み合わせて使えばいいのです
(これに最初気付かなかった )

例えば、!#$という風に$を付けると、「直前の引数」を参照できます。

つまり、

cp path/to/file !#$.bak

cp path/to/file path/to/file.bak

になります

(ちなみにこれならcp path/to/file{,.bak}でもできますが)

また、

mv path/to/typo !#$:s/po/pe

mv path/to/typo path/to/type

になります

ちょっと使いどころが見えてきましたね?

しかも、!!!$などと違って、「それまでに実行したコマンド」の影響を受けないので、
むしろそれらより気軽に手順書とかに使えますね。

例えば、たくさんの設定ファイルを所定の場所に配置する、と言った場合、普通に書くと以下のようになります。
※サーバー上に配置するファイルを、どこか(ホームディレクトリとか)のdeploy_filesディレクトリ下に、ディレクトリ構造を保った状態で一旦配置して、そこからコピーする場合を想定

cp deploy_files/pathA/to/fileA /pathA/to/fileA
cp deploy_files/pathB/to/fileB /pathB/to/fileB
cp deploy_files/pathC/to/fileC /pathC/to/fileC

別にコピペで済むんですけど、いちいち2箇所書き換えるのが面倒です。

これが、!#を使うとこう書けます。

cp deploy_files/pathA/to/fileA !#$:s/deploy_files/
cp deploy_files/pathB/to/fileB !#$:s/deploy_files/
cp deploy_files/pathC/to/fileC !#$:s/deploy_files/

書き換えるのが一箇所で済むようになりました


それでは良きCLIライフを