Bash の履歴は非常に強力です。 bash 履歴拡張を効果的に使用する方法を理解すると、Linux コマンド ラインでの生産性が大幅に向上します。
この記事では、次の bash 履歴拡張機能を使用する 15 の例について説明します:
- イベント指定子 – 履歴内の特定のコマンドを参照します。 !で始まります
- 単語指定子 – 履歴エントリの特定の単語を参照します。通常、これは偶数指定子と組み合わされます。指定子と単語指定子もコロンで区切ります
- 修飾子 – イベントまたは単語指示子によって行われた置換の結果を変更します
この記事は、進行中の Bash チュートリアル シリーズの一部です。
ご存じのとおり、すべての履歴エントリを表示するには、history コマンドを使用します。これにより、以前に実行されたすべてのコマンドが、履歴テーブル内のそのコマンドの番号とともに表示されます。
$ history 1 tar cvf etc.tar /etc/ 2 cp /etc/passwd /backup 3 ps -ef | grep http 4 service sshd restart 5 /usr/local/apache2/bin/apachectl restart
Bash 履歴イベント指定子
1. !n を使用して履歴から特定のコマンドを実行します
以前にコマンドを実行したことがある場合は、再度入力する代わりに、履歴内のコマンドの対応する番号を使用してすばやく実行できます。
たとえば、コマンド #4 を実行するには、次のようにします。これにより、履歴からコマンド #4 が表示され、すぐに実行されます。
$ !4 service sshd restart
2 つ前のコマンドを入力したコマンドを実行するには、次のようにします。
$ !-2
前のコマンドを実行するには、次のいずれかを実行します:
$ !! $ !-1
「set -o vi」を使用してコマンド ラインで vi スタイルの編集を有効にした場合は、
2. !string と !?string を使用してキーワードでコマンドを実行します
キーワードを使用して履歴からコマンドを実行することもできます。
次の例では、キーワードで始まる前のコマンドを検索します。 「ps」を押して実行してください。この例では、前のコマンド「ps -ef | grep http」を実行します。
$ !ps ps -ef | grep http
次の例では、キーワードを含む前のコマンドを検索します。 「apache」を実行してください。この例では、前のコマンド「/usr/local/apache2/bin/apachectl restart」を取得して実行します。
$ !?apache /usr/local/apache2/bin/apachectl restart
3. ^str1^str2^
を使用して、前のコマンドの文字列を置き換えます次の例では、最初に ls コマンドを実行してファイルを検証しています。後で、ファイルの内容を表示したいことに気付きました。ファイル名全体をもう一度入力する代わりに、以下に示すように、前のコマンドの「ls」を「cat」に置き換えるだけです。
$ ls /etc/cron.daily/logrotate $ ^ls^cat^ cat /etc/cron.daily/logrotate
注:その他の bash 履歴のヒントについては、「Linux コマンド ライン履歴をマスターするための 15 の例」を参照してください。これは、履歴にタイムスタンプを表示する方法と、HISTTIMEFORMAT、HISTSIZE、HISTFILE、HISTCONTROL、および HISTIGNORE を含むさまざまな履歴関連の環境変数を使用する方法を説明します
Bash 履歴ワード指定子
新しいコマンドを入力したいが、以前に実行されたコマンドの 1 つからの引数を使用したい場合、単語指示子は非常に役立ちます。例のいくつかを以下に示します。
4. :^
を使用して、コマンドの第 1 引数を取得します。次の例では、「ls -l」コマンドの引数として「!cp:^」を指定しています。 「!cp:^」は、「cp」で始まる履歴内の前のコマンドを見つけ、そのコマンドの 1 番目の引数を取得します。
$ cp /etc/passwd /backup $ ls -l !cp:^ ls -l /etc/passwd
次の例は、前のコマンドから 1 番目の引数を取得します。
$ ls -l !!:^
5. :$
を使用して、コマンドの最後の引数を取得します次の例では、「ls -l」コマンドの引数として「!cp:$」を指定しています。 「!cp:$」は、「cp」で始まる履歴内の前のコマンドを見つけ、そのコマンドの最後の引数を取得します。
$ cp /etc/passwd /backup $ ls -l !cp:$ ls -l /backup
次の例は、前のコマンドから最後の引数を取得します。
$ls -l !!:$
6. :n を使用してコマンドの n 番目の引数を取得します
次の例では、「ls -l」コマンドの引数として「!tar:2」が指定されています。 「!tar:2」は、「tar」で始まる履歴内の前のコマンドを見つけ、そのコマンドの 2 番目の引数を取得します。
$ tar cvfz /backup/home-dir-backup.tar.gz /home $ ls -l !tar:2 ls -l /backup/home-dir-backup.tar.gz
7. :* を使用してコマンドからすべての引数を取得します
次の例では、「ls -l」コマンドの引数として「!cp:*」を指定しています。 「!cp:*」は、「cp」で始まる履歴内の前のコマンドを見つけ、すべての引数を取得します。
$ cp /etc/passwd /backup $ ls -l !cp:* ls -l /etc/passwd /backup
8. !% を使用して最近検索した単語を参照
上記で説明したように、「!?apache」はキーワード「apache」を含む以前の履歴コマンドを検索して実行します。
$ /usr/local/apache2/bin/apachectl restart $ !?apache /usr/local/apache2/bin/apachectl restart
!% は、前の「?」によって一致した単語全体を参照します。検索してください。
たとえば、以前に「?apache」を検索した場合、「!%」は「/usr/local/apache2/bin/apachectl」という単語全体に一致します。このコンテキストでは、「/」は 1 つの単語の一部として扱われることに注意してください。
というわけで、この場合は以下を実行することでapacheを止めることができます。
$ !% stop /usr/local/apache2/bin/apachectl stop
9. x-y を使用してコマンドから引数の範囲を取得
以下の例では、「ls -l」コマンドの引数に「!tar:3-5」を指定しています。 「!tar:3-5」は、「tar」で始まる履歴内の前のコマンドを見つけ、3 から 5 までの引数を取得します。
$ tar cvf home-dir.tar john jason ramesh rita $ ls -l !tar:3-5 ls -l john jason ramesh
以下は、2 からすべての引数を取得します。
$ ls -l !tar:2-$
次の点に注意してください:
- !!:* 前のコマンドからすべての引数を取得します
- !!:2* 2 番目の引数から始まるすべての引数を取得します。
- !!:2-$ 上と同じ。 2 番目の引数から始まるすべての引数を取得します。
- !!:2- 2 番目の引数から始まるすべての引数を取得します (最後の引数を除く)。
Bash 履歴修飾子
以下の例で説明するように、修飾子は指定子の後に指定します。
10. :h を使用して単語から末尾のパス名を削除します
次の例では、「!!:$:h」は前のコマンドの最後の引数を取り、末尾のパス名を削除します。この場合、ファイル名を削除し、フル パスのみを取得します。
$ ls -l /very/long/path/name/file-name.txt $ ls -l !!:$:h ls -l /very/long/path/name
11. :t を使用して単語から先頭のパス名をすべて削除します
これは前の例とは正反対です。
次の例では、「!!:$:t」は前のコマンドの最後の引数を取り、先頭のパス名をすべて削除します。この場合、ファイル名のみを取得します。
$ ls -l /very/long/path/name/file-name.txt $ ls -l !!:$:t ls -l file-name.txt
12. :r を使用して単語からファイル名拡張子を削除します
次の例では、「!!:$:r」は前のコマンドの最後の引数を取り、「.suffix」(ここではファイル名拡張子) のみを削除します。この場合、.txt を削除しました
$ ls -l /very/long/path/name/file-name.txt $ ls -l !!:$:r ls -l /very/long/path/name/file-name
13. :s/str1/str2/
を使用して、bash 履歴での Sed のような置換前述のように「^元の^置換^」を使用する代わりに、以下の例に示すように、bash 履歴で sed のような置換を使用することもできます。これは覚えやすいかもしれません。 !!前のコマンドを呼び出すことです。「:s/original-string/replacement-string/」は、文字列を置き換える sed のような構文です。
$ !!:s/ls -l/cat/
以下に示すように、g フラグ (s フラグと一緒に) を使用してグローバルな置換を行うこともできます。これは、複数の単語を間違って入力し、それらすべてをまとめて変更してコマンドを再度実行したい場合に役立ちます。
次の例では、誤って「password」を (passwd ではなく) 2 回指定しています。
$ cp /etc/password /backup/password.bak
これを修正するには、次のグローバル履歴を置換のように実行します。
$ !!:gs/password/passwd/ cp /etc/passwd /backup/passwd.bak
14. :&
を使用して、置換をすばやく繰り返します上記のように bash 履歴置換を既に正常に実行している場合は、:&を使用して同じ置換をもう一度すばやく繰り返すことができます。
別のコマンドで「passwd」ではなく「password」を間違ってもう一度入力してしまいました。
$ tar cvf password.tar /etc/password
これで、コマンドを再入力したり、「gs/password/passwd」を実行したりする代わりに、「:&」を使用できます。これにより、最後の置換が再利用されます。最後の置換をグローバルに再利用するには、「:g&」を使用します。
$ !!:g& tar cvf passwd.tar /etc/passwd
15. :p を使用してコマンドを実行せずに出力します
これは、複雑な履歴置換を行う場合に非常に役立ち、実行する前に最終コマンドを確認したい場合に役立ちます。
次の例の「!tar:3-:p」は、実際にはコマンドを実行しません。
ここで「:p」を指定したので、置換を行って新しいコマンドを表示するだけです。 bash 履歴の展開を確認したら、これが実行しようとしていたコマンドであると思われる場合は、「:p」を削除してもう一度実行してください。
$ tar cvf home-dir.tar john jason ramesh rita $ tar cvfz new-file.tar !tar:3-:p tar cvfz new-file.tar john jason ramesh