historyは、これまでに実行したコマンドの履歴を番号つきで表示するコマンドです。 表示するだけでなく、Ctrl+R で検索して再実行したり、!! や !$ で直前のコマンドを使い回したり、history -d で特定の履歴を消したりできます。保存件数は HISTSIZE、記録しないルールは HISTCONTROL で決まります。

この記事では、bash と zsh の両方について、実際に動かした結果を付けてまとめました。Ctrl+R で戻りすぎたときの Ctrl+S が効かない原因(stty -ixon)、履歴展開の早見表、bash と zsh の設定対応表、そのまま貼れる .bashrc/.zshrc、そしてパスワードをうっかり打ってしまったときの削除手順と、「消したのに残っている」原因を、端末を2つ開いた状態で再現して確かめています。

検証環境は Ubuntu 24.04 LTS、bash 5.2.21、zsh 5.9 です。キー操作(Ctrl+R など)は疑似端末を通して送り、画面に出た文字列を記録しました。fzf との連携と macOS での動作は手元で動かしていないため、該当箇所に「未実行」と明記しています。

historyコマンドの早見表

やりたいことから選ぶ(bash)

やりたいこと 操作・コマンド
履歴を全部表示する history
最近の10件だけ表示する history 10
履歴を検索して再実行する Ctrl+R を押して文字を入力 → Enter
さらに前の候補へ もう一度 Ctrl+R
戻りすぎたので新しい方へ Ctrl+S(先に stty -ixon が必要)
検索をやめる Ctrl+G
文字列を含む履歴を一覧する history | grep 文字列
直前のコマンドをもう一度 !!
直前のコマンドの最後の引数を使う !$
番号を指定して再実行 !42
直前のコマンドの一部を直して再実行 ^old^new
実行日時を表示する HISTTIMEFORMAT='%F %T ' を設定
1件だけ消す history -d 番号
範囲で消す history -d 開始-終了
メモリ上の履歴を全部消す history -c
いまの履歴をファイルに書き出す history -w
このコマンドは履歴に残さない 先頭にスペースを付ける(HISTCONTROL=ignorespace)

history のオプション(bash 5.2)

書き方 働き
history 履歴を番号つきで全件表示
history N 最後の N 件を表示
history -c メモリ上の履歴リストを消す
history -d 番号 指定した番号の履歴を消す(負の数は末尾から数える)
history -d 開始-終了 範囲をまとめて消す
history -a このセッションで増えた分を履歴ファイルに追記する
history -n 履歴ファイルから、まだ読んでいない行を読み込む
history -r 履歴ファイルを読んで、メモリ上の履歴に追加する
history -w メモリ上の履歴で、履歴ファイルを上書きする
history -p 引数 履歴展開の結果だけを表示する(実行も記録もしない)
history -s 引数 引数を1件の履歴として追加する

この書式と説明は、Bash リファレンスマニュアルの「Bash History Builtins」で確認しました。

履歴にかかわる変数(bash)

変数 意味 何も設定しないとき Ubuntu 24.04 の初期 .bashrc
HISTSIZE メモリ上に持つ件数 500 1000
HISTFILESIZE 履歴ファイルに残す行数 500 2000
HISTFILE 履歴ファイルの場所 ~/.bash_history 変更なし
HISTCONTROL 記録しないルール 空 ignoreboth
HISTIGNORE 記録しないパターン(コロン区切り) 空 設定なし
HISTTIMEFORMAT 日時の表示形式 空(日時なし) 設定なし

「何も設定しないとき」は bash --norc で起動して確かめた値、右端は /etc/skel/.bashrc に書かれている値です。

本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。

(記載例)出典:株式会社RJC「historyコマンドの使い方|Ctrl+R検索・履歴削除・HISTSIZE」

履歴を表示する

history と history N

history
    1  echo 1
    2  echo 2
    3  echo 3
    4  echo 4
    5  echo 5
    6  history

左の数字が履歴番号です。あとで出てくる !番号 や history -d 番号 で使います。件数が多いときは、最後の数件だけに絞れます。

history 3
    6  mkdir -p /tmp/t179demo/app
    7  history
    8  history 3

history 自身も履歴に入るので、最後の行は必ず今打ったコマンドになります。

文字列で絞り込む

history | grep mkdir

パイプで grep に渡すと、該当する行だけを番号つきで見られます。見つけた番号は !番号 でそのまま再実行できます。

実行日時を表示する(HISTTIMEFORMAT)

HISTTIMEFORMAT='%F %T  '
echo a
history 2
    3  2026-10-03 00:57:32  echo a
    4  2026-10-03 00:57:32  history 2

%F は年-月-日、%T は時:分:秒です。この変数を設定すると、履歴ファイルにも時刻が記録されるようになります。 ファイルの中身は次のようになります。

history -w
cat $HISTFILE
#1790956744
HISTTIMEFORMAT='%F %T  '
#1790956744
echo a
#1790956745
history -w

# に続く数字は UNIX 時間(1970年からの秒数)です。

Ctrl+Rで履歴を検索する

基本の流れ

履歴に echo alpha、echo beta、echo gamma、ls /tmp、echo delta が入っている状態で試しました。

  1. Ctrl+R を押すと、プロンプトが (reverse-i-search) に変わります。
  2. echo と入力すると、新しい方から探して最初に見つかったコマンドが表示されます。
  3. もう一度 Ctrl+R を押すと、1つ前の候補に移ります。
(reverse-i-search)`echo': echo delta      ← echo と入力
(reverse-i-search)`echo': echo gamma      ← Ctrl+R
(reverse-i-search)`echo': echo beta       ← Ctrl+R

目的のコマンドが出たら、次のキーで操作します。

キー 動き
Enter 表示中のコマンドをそのまま実行する
→ または Ctrl+E など 実行せず、入力行に取り込んで編集する
Ctrl+R さらに前(過去の方)の候補へ
Ctrl+S 後ろ(新しい方)の候補へ(設定が必要。次の項)
Ctrl+G 検索をやめて元の入力行に戻る

bash のキー割り当ては bind -p で確かめられます。

bind -p | grep -e reverse-search-history -e forward-search-history
"\C-s": forward-search-history
"\C-r": reverse-search-history

Ctrl+S には、はじめから「前方検索(forward-search-history)」が割り当てられています。

Ctrl+Sが効かない原因はフロー制御(ixon)

ところが、多くの端末では Ctrl+S を押しても何も起きません。上の続きで Ctrl+S を送ったときの記録です。

(reverse-i-search)`echo': echo beta       ← ここで Ctrl+S
(画面は変わらない。続けて Ctrl+R を押しても表示されない)
(reverse-i-search)`echo': echo alpha      ← Ctrl+Q を押すと、止まっていた分が表示される

原因は、端末の「フロー制御」という機能です。 Ctrl+S は「画面への出力を一時停止(XOFF)」、Ctrl+Q は「再開(XON)」という意味で、bash に届く前に端末が受け取ってしまいます。そのため画面が固まったように見え、Ctrl+Q を押すと、止まっていた間のキー入力の結果がまとめて出てきます。

現在の設定は stty -a で確かめられます。

stty -a | tr ' ;' '\n\n' | grep -x -e ixon -e -ixon
ixon

ixon と出ればフロー制御が有効、-ixon なら無効です。

直し方:stty -ixon

stty -ixon
stty -a | tr ' ;' '\n\n' | grep -x -e ixon -e -ixon
-ixon

無効にしてから同じ操作をすると、Ctrl+S が bash に届きます。

(reverse-i-search)`echo': echo delta      ← echo と入力
(reverse-i-search)`echo': echo gamma      ← Ctrl+R
(reverse-i-search)`echo': echo beta       ← Ctrl+R
(i-search)`echo': echo beta               ← Ctrl+S(表示が i-search に変わった)

プロンプトが (reverse-i-search) から (i-search) に変わり、検索の向きが「新しい方へ」に切り替わりました。この向きのまま、新しい方の候補をたどれます。

毎回打たなくて済むように、~/.bashrc に書いておきます。 対話シェルのときだけ実行するのがコツです(スクリプトや scp などで端末がないときに stty がメッセージを出さないようにするため)。

if [[ $- == *i* ]]; then
  stty -ixon
fi
症状 原因 対処
Ctrl+S で画面が固まったように見える フロー制御で出力が止まっている Ctrl+Q で再開
Ctrl+S で前方検索にならない ixon が有効 stty -ixon を .bashrc に書く
zsh で同じことが起きる FLOW_CONTROL オプションが有効 unsetopt FLOW_CONTROL(または stty -ixon)

zsh 5.9 でも、初期状態では Ctrl+S を送っても画面に変化がなく、unsetopt FLOW_CONTROL を実行したあとは反応することを確かめました。zsh の Ctrl+R/Ctrl+S は history-incremental-search-backward/forward に割り当てられています(bindkey で確認)。

fzfと組み合わせる(未実行)

fzf(あいまい検索ツール)を入れると、Ctrl+R が「候補を一覧で見ながら絞り込む」画面に変わります。この連携は今回動かしていません(未実行)。 手元で確認できたのは、Ubuntu 24.04 の apt で入る fzf が 0.44.1 であることと、絞り込み自体の動きです。

printf 'echo alpha\nls /tmp\necho beta\ngit status\n' | fzf --filter 'ech'
echo beta
echo alpha

一般に知られた設定方法としては、fzf 0.48 以降なら .bashrc に eval "$(fzf --bash)"、.zshrc に source <(fzf --zsh) を書きます。apt 版のようにそれより前の版では、パッケージに付属するキーバインド用スクリプト(key-bindings.bash/key-bindings.zsh)を source します。導入するときは fzf --version で版を確かめてください。

履歴展開の早見表(!!・!$・!番号・^old^new)

! で始まる書き方は履歴展開と呼ばれ、過去のコマンドやその一部を呼び出せます。bash は、展開後のコマンドを1行表示してから実行します。

イベント(どのコマンドか)を指定する

書き方 意味 実行例(→ 展開結果)
!! 直前のコマンド !! → echo hello
!番号 その番号のコマンド !3 → cd /tmp
!-N N個前のコマンド !-2 → pwd
!文字列 その文字列で始まる最新のコマンド !echo → echo hello world
!?文字列? その文字列を含む最新のコマンド !?hostname? → ls /etc/hostname
^old^new 直前のコマンドの old を new に変えて実行 ^helo^hello → echo hello

単語(引数)を取り出す

書き方 意味 実行例(直前が echo a b c や echo one two three)
!$ 直前のコマンドの最後の引数 cd !$ → cd /tmp/t179demo/app
!^ 直前のコマンドの最初の引数 echo !^ → echo a
!* 直前のコマンドの引数すべて echo !* → echo a b c
!:N 直前のコマンドの N 番目の単語 echo !:2 → echo two

修飾子(展開結果を加工する)

書き方 意味 実行例
:p 実行せず表示だけする !ls:p → ls /etc/hostname と表示
:s/old/new/ 最初の old を new に置き換える !!:s/one/ONE/ → echo ONE two three
:gs/old/new/ すべての old を new に置き換える !!:gs/e/E/ → Echo ONE two thrEE

実行結果

よく使うものを実際に動かした記録です($ の行が入力、その次の行が bash の表示した展開結果です)。

$ mkdir -p /tmp/t179demo/app
$ cd !$
cd /tmp/t179demo/app
$ pwd
/tmp/t179demo/app

$ echo hello
hello
$ !!
echo hello
hello

$ ls /etc/hostname
/etc/hostname
$ cat !$ | wc -l
cat /etc/hostname | wc -l
1

$ echo helo
helo
$ ^helo^hello
echo hello
hello

$ echo one two three
one two three
$ !!:s/one/ONE/
echo ONE two three
ONE two three

!$ は「mkdir したディレクトリに cd する」「ls で確かめたファイルを cat する」といった流れで役立ちます。 !! は、権限が足りなかったコマンドを sudo !! でやり直す使い方がよく知られています。

打ち間違いの直しには、!! のうしろに文字を足す方法もあります。

$ ls /etc/hostnam
ls: cannot access '/etc/hostnam': No such file or directory
$ !!e
ls /etc/hostname
/etc/hostname

該当する履歴が無いとき

$ !999
bash: !999: event not found

event not found は「その番号(または文字列)の履歴が無い」という意味です。

「!」を含む文字列で意図しない展開が起きるとき

ダブルクォートの中でも ! は展開されます。

$ echo "it works!!"
echo "it worksecho "done!""
it worksecho done!

$ echo 'it works!!'
it works!!

1つ目は !! が直前のコマンド(echo "done!")に置き換わっています。! を文字として使いたいときは、シングルクォートで囲みます。 履歴展開そのものを止めたいときは set +H です。

$ set +H
$ echo "wow!!"
wow!!

展開結果を確かめてから実行する(histverify)

!! や !番号 は、Enter を押した時点で実行されます。何が実行されるか確かめてからにしたいときは、:p を付けるか、shopt -s histverify を設定します。 histverify を有効にすると、展開結果が入力行に置かれ、もう一度 Enter を押すまで実行されません。

$ shopt -s histverify
$ !!
$ shopt -s histverify     ← 展開された状態で止まる。Enter で実行

消すコマンド(rm など)を履歴から呼び出すことがあるなら、設定しておくと落ち着いて確認できます。

HISTSIZE・HISTFILESIZE・HISTCONTROLで保存の仕方を決める

メモリとファイルの関係

bash の履歴は、メモリ上のリストと履歴ファイル(~/.bash_history)の2か所にあります。

flowchart LR
  A[bash 起動] -->|ファイルを読み込む| B[メモリ上の履歴]
  B -->|コマンドを打つたびに追加| B
  B -->|終了時に書き出す| C[~/.bash_history]
  B -.->|history -a / -w| C
  C -.->|history -r / -n| B

打ったコマンドは、まずメモリにだけ入り、ファイルに書かれるのはシェルを終了するときです(history -a や history -w を実行すれば、その時点で書かれます)。この仕組みが、あとで出てくる「消したはずなのに残っている」の理由になります。

HISTSIZE:メモリに持つ件数

$ echo $HISTSIZE $HISTFILESIZE
500 500
$ HISTSIZE=5
$ echo 1
(中略:echo 6 まで実行)
$ history
    6  echo 3
    7  echo 4
    8  echo 5
    9  echo 6
   10  history

HISTSIZE=5 にすると、メモリに残るのは最新の5件だけになりました。

HISTFILESIZE:ファイルに残す行数

8行ある履歴ファイルに対して、値を小さくしてみます。

$ wc -l < $HISTFILE
8
$ HISTFILESIZE=4
$ wc -l < $HISTFILE
4
$ cat $HISTFILE
echo old5
echo old6
echo old7
echo old8

HISTFILESIZE を設定した時点で、ファイルが新しい方から4行に切り詰められました。 小さい値を試しに入れると過去の履歴がその場で減るので、値を変えるときは大きい方へ変えるのが無難です。

HISTCONTROL:記録しないルール

値 働き
ignorespace 先頭がスペースのコマンドを記録しない
ignoredups 直前と同じコマンドを記録しない
ignoreboth 上の2つを両方
erasedups 同じコマンドが過去にあれば、以前の分を消してから記録する
$ HISTCONTROL=ignoreboth
$  echo secret-with-space        ← 先頭にスペース
secret-with-space
$ echo dup
dup
$ echo dup
dup
$ echo dup
dup
$ history 4
    5  2026-10-03 00:57:32  echo $HISTCONTROL
    6  2026-10-03 00:57:33  HISTCONTROL=ignoreboth
    7  2026-10-03 00:57:34  echo dup
    8  2026-10-03 00:57:35  history 4

スペースで始めたコマンドは記録されず、3回打った echo dup は1件にまとまっています。

HISTIGNORE:パターンで除外する

HISTIGNORE='ls:pwd:history*'

コロン区切りでパターンを並べます。パターンは「コマンド行の全体」と照合されます。 ls と書いた場合に除外されるのは ls だけの行で、ls >/dev/null や ls -l は記録されました。引数つきも除外したいときは ls* のように * を付けます。

$ HISTIGNORE='ls:pwd:history*'
$ ls >/dev/null
$ pwd >/dev/null
$ echo kept
kept
$ history 3
   12  2026-10-03 00:57:37  ls >/dev/null
   13  2026-10-03 00:57:38  pwd >/dev/null
   14  2026-10-03 00:57:38  echo kept

(history 3 自体は history* に当てはまるため、記録されていません。)

一時的に記録を止める

方法 動き 確認した結果
先頭にスペースを付ける その1行だけ記録しない HISTCONTROL=ignorespace(または ignoreboth)のときに有効
set +o history … set -o history はさまれた間のコマンドを記録しない set +o history 自体は記録され、間のコマンドは記録されなかった
unset HISTFILE このセッションの履歴をファイルに書かない 終了後のファイルは元のままだった

bashとzshの設定対応表

zsh にも履歴の機能がありますが、変数名と設定方法が少し違います。

設定したいこと bash zsh
メモリ上の件数 HISTSIZE HISTSIZE
ファイルに保存する件数 HISTFILESIZE SAVEHIST
履歴ファイル HISTFILE(既定 ~/.bash_history) HISTFILE(自分で設定する。よく使われるのは ~/.zsh_history)
直前と同じコマンドを記録しない HISTCONTROL=ignoredups setopt HIST_IGNORE_DUPS
過去の重複を消す HISTCONTROL=erasedups setopt HIST_IGNORE_ALL_DUPS
先頭スペースを記録しない HISTCONTROL=ignorespace setopt HIST_IGNORE_SPACE
パターンで除外 HISTIGNORE='ls:pwd' HISTORY_IGNORE='(ls|pwd)'(ファイルへの保存時に除外)
終了時に追記する shopt -s histappend setopt APPEND_HISTORY(初期状態で有効)
1コマンドごとにファイルへ書く PROMPT_COMMAND='history -a' setopt INC_APPEND_HISTORY
複数端末で共有する PROMPT_COMMAND='history -a; history -n' setopt SHARE_HISTORY
日時を記録する HISTTIMEFORMAT='%F %T ' setopt EXTENDED_HISTORY
日時つきで表示する history(上の変数を設定済み) history -i
全件表示する history history 1(history だけだと最近の分だけ)
展開を確かめてから実行 shopt -s histverify setopt HIST_VERIFY
Ctrl+S を前方検索に使う stty -ixon unsetopt FLOW_CONTROL
1件削除 history -d 番号 専用のオプションは無い(ファイルを編集して読み直す)
全消去 history -c history -c は使えない

zsh のオプションの意味は、zsh 公式マニュアルの「Options」のページで確認しました。

zsh で確かめたこと

zsh -f(設定ファイルを読まない起動)での初期値です。

% echo "HISTSIZE=$HISTSIZE SAVEHIST=$SAVEHIST"
HISTSIZE=30 SAVEHIST=0

SAVEHIST の初期値は 0 で、HISTFILE も未設定です。 このままではシェルを閉じると履歴が残りません(終了後に履歴ファイルが作られていないことを確認しました)。ディストリビューションや macOS では、あらかじめ用意された設定ファイルで値が入っていることもあるので、echo $HISTSIZE $SAVEHIST $HISTFILE で確かめてみてください。

!!、!$、!*、!-2、^old^new、:p は zsh でも同じように使えました。

% echo helo
helo
% ^helo^hello
echo hello
hello

一方、history -d と history -c は bash と意味が違います。

% history -c
history: bad option: -c
% history -d 2
    2  01:00  echo $ZSH_VERSION
    3  01:00  echo "HISTSIZE=$HISTSIZE SAVEHIST=$SAVEHIST"
    4  01:00  echo one
(以下略)

zsh の history -d は「削除」ではなく「時刻つきで表示」でした。bash の感覚で打つと、消えたつもりで残っていることになるので、zsh での消し方は後の項で説明します。

EXTENDED_HISTORY を有効にしたときの履歴ファイルは、次の形式です。

: 1790956833:0;HISTSIZE=1000; SAVEHIST=1000
: 1790956835:0;echo dup
: 1790956835:0;fc -W

: 開始時刻:所要秒数;コマンド の並びです。history -i で日時つきの表示になります。

% history -i -2
    6  2026-10-03 01:00  fc -W
    7  2026-10-03 01:00  cat $HISTFILE

コピペ用の.bashrcと.zshrc

どちらも、実際に読み込ませて動作を確かめたものです。~/.bashrc または ~/.zshrc の末尾に貼り、source ~/.bashrc(zsh は source ~/.zshrc)か、端末を開き直すと有効になります。

.bashrc(bash 5.2 で確認)

# ===== コマンド履歴の設定(bash) =====
HISTSIZE=10000                       # メモリ上に持つ件数
HISTFILESIZE=20000                   # ~/.bash_history に残す行数
HISTCONTROL=ignoreboth:erasedups     # 先頭スペース・連続重複を記録しない/過去の重複を消す
HISTIGNORE='ls:ll:pwd:exit:clear:history'   # 完全一致したコマンドは記録しない
HISTTIMEFORMAT='%F %T  '             # history に実行日時を表示する
shopt -s histappend                  # 終了時に上書きせず追記する
shopt -s cmdhist                     # 複数行のコマンドを1件にまとめる
shopt -s histverify                  # !! などを即実行せず、いったん入力行に展開する

# 対話シェルのときだけ:Ctrl+S を前方検索に使えるようにする
if [[ $- == *i* ]]; then
  stty -ixon
  bind '"\e[A": history-search-backward'   # ↑:入力済みの文字で始まる履歴をさかのぼる
  bind '"\e[B": history-search-forward'    # ↓:その逆
fi

# 複数の端末で履歴をすぐ共有したい場合は、次の行のコメントを外す
# PROMPT_COMMAND="history -a; history -n${PROMPT_COMMAND:+; $PROMPT_COMMAND}"

読み込ませたあとの確認結果です。

$ echo "$HISTSIZE $HISTFILESIZE $HISTCONTROL"
10000 20000 ignoreboth:erasedups
$ stty -a | tr ' ;' '\n\n' | grep -x -e ixon -e -ixon
-ixon
$ shopt histappend cmdhist histverify
histappend      on
cmdhist         on
histverify      on
$ bind -p | grep 'history-search'
"\e[A": history-search-backward
"\e[B": history-search-forward

この状態で ls、pwd、先頭スペースつきの echo hidden、echo dup を2回、と打ったあとの history 4 です。ls・pwd・スペースつきのコマンドは記録されず、echo dup は1件にまとまっています。

    3  2026-10-03 01:07:29  stty -a | tr ' ;' '\n\n' | grep -x -e ixon -e -ixon
    4  2026-10-03 01:07:30  ls >/dev/null; pwd
    5  2026-10-03 01:07:31  echo dup
    6  2026-10-03 01:07:32  history 4

最後の PROMPT_COMMAND の行は、端末どうしで履歴をすぐ共有できる代わりに、後で説明する「履歴の削除」の手順が1つ増えます。必要になってから有効にするのでも十分です。

.zshrc(zsh 5.9 で確認)

# ===== コマンド履歴の設定(zsh) =====
HISTFILE=~/.zsh_history       # 保存先(未設定だと保存されない)
HISTSIZE=10000                # メモリ上に持つ件数
SAVEHIST=10000                # ファイルに保存する件数(初期値は 0)
setopt EXTENDED_HISTORY       # 実行日時と所要時間も保存する
setopt HIST_IGNORE_DUPS       # 直前と同じコマンドは記録しない
setopt HIST_IGNORE_ALL_DUPS   # 過去の同じコマンドを消して新しい方を残す
setopt HIST_IGNORE_SPACE      # 先頭がスペースのコマンドは記録しない
setopt HIST_REDUCE_BLANKS     # 余分な空白を詰めて記録する
setopt HIST_SAVE_NO_DUPS      # ファイルに書くとき重複を省く
setopt HIST_VERIFY            # !! などを即実行せず、いったん入力行に展開する
setopt SHARE_HISTORY          # 複数の端末で履歴を共有する
HISTORY_IGNORE='(ls|ll|pwd|exit|clear|history)'   # ファイルに保存しないコマンド

# Ctrl+S を前方検索に使えるようにする
unsetopt FLOW_CONTROL
bindkey '^R' history-incremental-search-backward
bindkey '^S' history-incremental-search-forward

# ↑↓:入力済みの文字で始まる履歴をたどる
autoload -Uz up-line-or-beginning-search down-line-or-beginning-search
zle -N up-line-or-beginning-search
zle -N down-line-or-beginning-search
bindkey '^[[A' up-line-or-beginning-search
bindkey '^[[B' down-line-or-beginning-search

# 日時つきで全件表示
alias h='history -i 1'

読み込ませたあとの確認結果です。

% echo "$HISTSIZE $SAVEHIST"
10000 10000
% echo $options[flowcontrol] $options[sharehistory]
off on
% bindkey | grep -e '\^R' -e '\^S' -e '\[A'
"^R" history-incremental-search-backward
"^S" history-incremental-search-forward
"^[[A" up-line-or-beginning-search

ls >/dev/null、pwd、先頭スペースつきの echo hidden、空白を多めに入れた echo dup x、echo dup x と打ったあとの h | tail -4 です。

    2  2026-10-03 01:07  echo "$HISTSIZE $SAVEHIST"
    3  2026-10-03 01:07  ls >/dev/null
    4  2026-10-03 01:07  pwd
    5  2026-10-03 01:07  echo dup x

スペースつきのコマンドは記録されず、空白が詰められて重複が1件になっています。pwd はメモリ上には残っていますが、終了後の履歴ファイルには書かれていませんでした(HISTORY_IGNORE はファイルへの保存時に効きます)。

パスワードを打ってしまったときの履歴削除手順

mysql -u app -pS3cretPass のように、コマンドの引数にパスワードを書いて実行してしまった場面を想定します(以下の S3cretPass は検証用の文字列です)。

手順の全体像

順番 やること bash のコマンド
1 該当する履歴番号を調べる history | grep 'mysql -u'
2 メモリ上の履歴から消す history -d 番号
3 履歴ファイルを書き直す history -w
4 ファイルに残っていないか確かめる grep -c 'mysql -u app' ~/.bash_history
5 ほかに開いている端末でも読み直す history -c; history -r
6 パスワードそのものを変更する 各サービスの手順で

6 がいちばん大切です。 履歴から消しても、実行中はプロセス一覧に引数が見えていた可能性があります。履歴の掃除は「これ以上残さないため」、パスワードの変更は「元から安心できる状態に戻すため」と考えると整理できます。

1 で検索するときは、パスワードの文字列ではなくコマンド名など別の部分で探します。パスワードで検索すると、その grep コマンド自体が履歴に入るからです(history | grep S3cret と打ったところ、その行が新しい履歴として追加されました)。

基本の手順(bash・端末が1つのとき)

$ history
    1  echo old1
    2  echo old2
    3  echo one
    4  mysql -u app -pS3cretPass 2>/dev/null
    5  echo two
    6  history
$ history -d 4
$ history -d -1
$ history
    1  echo old1
    2  echo old2
    3  echo one
    4  echo two
    5  history
    6  history -d 4
    7  history
$ history -w
$ grep -c S3cretPass $HISTFILE
0

history -d 4 で4番が消え、後ろの番号が1つずつ繰り上がりました。history -d -1 は「末尾の1件」を消す書き方で、ここでは直前に打った history -d -1 自身を消しています。history -w でメモリの内容をファイルに書き出すと、ファイル側からも無くなります(最後の grep -c が 0)。

なお、この検証ではシェルを終了したときに、このセッションのコマンドがもう一度ファイルに追記されて行が重複しましたが、パスワードの行は含まれていませんでした。

範囲でまとめて消す

$ history
    1  echo 1
    2  echo 2
    3  echo 3
    4  echo 4
    5  echo 5
    6  history
$ history -d 2-4
$ history
    1  echo 1
    2  echo 5
    3  history
    4  history -d 2-4
    5  history

開始-終了 の形で、2番から4番までをまとめて消せます(bash 5.2 で確認)。パスワードを何度か打ち直した場合などに使えます。範囲外の番号を指定したときは、次のメッセージになります。

$ history -d 999
bash: history: 999: history position out of range

ファイル側を直接消す

履歴ファイルはテキストなので、エディタや sed で該当行を消せます。

 sed -i '/S3cretPass/d' "$HISTFILE"

先頭にスペースを付けて実行すると、HISTCONTROL=ignorespace(または ignoreboth)のとき、この sed コマンド自体が履歴に残りません。ただし、ファイルだけを消しても、開いている端末のメモリには残っています。

$ sed -i '/mysql -u app/d' $HISTFILE
$ grep -c 'mysql -u' $HISTFILE
0
$ history | grep -c 'mysql -u app -p'
2

ファイルは 0 件になりましたが、メモリ上の history にはまだ見つかります(2 件のうち1件は、今打った grep 自身です)。この状態では ↑ キーや Ctrl+R でパスワードつきのコマンドが出てきますし、まだファイルに書かれていない履歴は終了時に書き出されます。ファイルを消したら、続けて history -c; history -r でメモリを読み直すのが確実です。

全部消してよいとき

$ history -c
$ history
    1  history
$ history -w
$ cat $HISTFILE
history
history -w

history -c でメモリを空にし、history -w で空の状態をファイルに書きます。履歴をすべて手放してよい場合の、いちばん短い手順です。

複数端末で履歴が消えない原因と対処

「消したのに、次にログインしたらまた出てきた」というときは、次のどれかに当てはまります。

原因 何が起きているか 対処
メモリだけ消した PROMPT_COMMAND='history -a' などで、打った直後にファイルへ書かれている history -d のあと history -w
ファイルだけ消した メモリに残っていて、↑ や Ctrl+R で出る。未保存分は終了時に書かれる history -c; history -r で読み直す
別の端末がメモリに持っている 共有設定(history -a; history -n や zsh の SHARE_HISTORY)で、ほかの端末にも読み込まれている ファイルを消してから、開いている端末すべてで読み直す
zsh で history -d を使った zsh の -d は削除ではなく日時表示 ファイルを編集して読み直す

再現1:メモリだけ消してもファイルに残る

PROMPT_COMMAND='history -a'(コマンドのたびにファイルへ追記)を設定した状態です。

$ PROMPT_COMMAND='history -a'
$ mysql -u app -pS3cretPass 2>/dev/null
$ history 3
    3  PROMPT_COMMAND='history -a'
    4  mysql -u app -pS3cretPass 2>/dev/null
    5  history 3
$ history -d -2
$ history 3
    4  mysql -u app -pS3cretPass 2>/dev/null
    5  history -d -2
    6  history 3
$ grep -n 'mysql -u' $HISTFILE
4:mysql -u app -pS3cretPass 2>/dev/null

この例では、history -d -2 で消そうとした mysql の行が残り、代わりに直前の history 3 が消えています。負の数は、今打っている history -d の行自身を -1 として数えるため、-2 は「1つ前に打ったコマンド」を指すからです。間に確認のコマンドをはさむと位置がずれるので、history で番号を確かめてから正の番号で指定する方が確実です。そして、メモリ側をどう消しても、すでに追記されたファイルの4行目はそのままです。history -w で上書きするまで残ります。

再現2:共有設定の2端末で、片方で消しても残る

端末AとBの両方に、次の共有設定を入れました。

HISTCONTROL=ignorespace
shopt -s histappend
PROMPT_COMMAND='history -a; history -n'

端末Aでパスワードつきのコマンドを打ち、端末Bで別のコマンドを打ったあと、端末Aで history を見ると、同じ行が2つありました。

[端末A]
$ history 4
    3  HISTCONTROL=ignorespace; shopt -s histappend; PROMPT_COMMAND='history -a; history -n'
    4  mysql -u app -pS3cretPass 2>/dev/null
    5  mysql -u app -pS3cretPass 2>/dev/null
    6  history 4

history -a で書いた自分の行を、history -n が「新しい行」としてもう一度読み込んだためです。ここで1件を history -d で消して history -w を実行しても、次のプロンプトで history -n がまた読み込み、history には同じ行が2件並んだままでした。別の端末からファイルを数えた結果です。

タイミング ファイル内の該当行の数
端末Aで打った直後 1
端末Aで history -d(1件)→ history -w のあと 2
端末B・端末Aを順に終了したあと 2

共有設定のもとでは、メモリの1件を消して書き出す方法だと、かえって行が増えることがありました。

対処:ファイルを先に消し、すべての端末で読み直す

同じ共有設定で、順番を変えます。コマンドはどれも先頭にスペースを付けて、履歴に残らないようにします。

[端末A]
$  sed -i '/S3cretPass/d' "$HISTFILE"
$  history -c; history -r

[端末B]
$  history -c; history -r
タイミング ファイル内の該当行の数
端末Aで sed と読み直しをしたあと 0
端末Bで読み直しをしたあと 0
両方の端末を終了したあと 0

「ファイルから消す → 開いている端末すべてで history -c; history -r」の順にすると、終了後も 0 件のままでした。 読み直しをしていない端末が1つでも残っていると、その端末のメモリから書き戻される可能性があるので、tmux や screen の中のシェル、SSH でつないだままの端末も忘れずに確かめます。

zsh での消し方

zsh には history -d にあたる削除オプションが無いため、履歴ファイルを編集してから、メモリを読み直します。 SHARE_HISTORY を設定した2つの端末で確かめました。

[端末A]
%  grep -c S3cretPass $HISTFILE
1
%  LC_ALL=C sed -i '/S3cretPass/d' $HISTFILE
%  grep -c S3cretPass $HISTFILE
0
%  history 1 | grep -c S3cretPass
1
%  fc -p $HISTFILE $HISTSIZE $SAVEHIST
%  history 1 | grep -c S3cretPass
0

sed のあともメモリには1件残っていて、fc -p $HISTFILE $HISTSIZE $SAVEHIST を実行すると 0 件になりました。 fc -p は、いまの履歴をいったん脇に置いて、指定したファイルから読み込み直すコマンドです。端末Bでも同じ fc -p を実行し、両方を終了したあとにファイルを数えると 0 件でした。

HIST_IGNORE_SPACE を有効にしておけば、zsh でも先頭スペースのコマンドは記録されません(上の例はすべて先頭にスペースを付けています)。

そもそも残さないために

方法 内容
パスワードを引数に書かない mysql -u app -p のように値を省くと、実行後に入力を求められる(画面にも履歴にも残らない)
先頭にスペースを付ける HISTCONTROL=ignoreboth(bash)/HIST_IGNORE_SPACE(zsh)を設定しておく
環境変数やファイルから読む 値をコマンド行に直接書かず、権限を絞った設定ファイルなどから渡す
作業のあいだ記録を止める set +o history … set -o history(bash)

1つ目の「引数に書かず、聞かれてから入力する」形が、いちばん手軽で確実です(この項の1つ目と3つ目は一般に知られた方法で、今回は実行していません)。

よくある質問

Q. history で表示される件数を増やすにはどうすればよいですか? A. bash は ~/.bashrc に HISTSIZE=10000 と HISTFILESIZE=20000 を書きます。zsh は HISTSIZE と SAVEHIST です。zsh の history は最近の分(一般に16件と知られています。今回は履歴が少なく件数までは未確認)だけを表示するので、全件を見たいときは history 1 とします。

Q. 端末を2つ開いていると、片方の履歴がもう片方に出てきません。 A. bash はシェルの終了時に履歴ファイルへ書き出すため、開いている最中はほかの端末から見えません。すぐ共有したいときは PROMPT_COMMAND='history -a; history -n'、zsh は setopt SHARE_HISTORY を設定します。bash 5.2 で設定なしの端末を2つ開いて順に閉じたところ、両方のコマンドがファイルに残っていました。shopt -s histappend を入れておくと、追記であることがはっきりします。

Q. Ctrl+S を押したら画面が固まりました。 A. 端末のフロー制御で出力が一時停止しています。Ctrl+Q を押すと再開します。前方検索として使いたいときは、~/.bashrc に stty -ixon(zsh は unsetopt FLOW_CONTROL)を書きます。

Q. sudo で実行したコマンドや、ほかのユーザーの履歴も見られますか? A. 履歴はユーザーごと・シェルごとに別のファイル(~/.bash_history など)に保存されます。history で見えるのは自分のシェルの履歴です。sudo コマンド と打った行は、自分の履歴に sudo つきで残ります。

まとめ

  • history で一覧、history N で最近の N 件。 HISTTIMEFORMAT を設定すると日時も表示・記録される
  • Ctrl+R で検索、もう一度押すと前の候補へ。 戻りすぎたら Ctrl+S。効かないときは stty -ixon
  • !! 直前、!$ 最後の引数、!番号、^old^new。 :p や histverify で実行前に確かめられる
  • bash は HISTSIZE/HISTFILESIZE/HISTCONTROL、zsh は HISTSIZE/SAVEHIST/setopt。 zsh は SAVEHIST と HISTFILE を設定しないと保存されない
  • 履歴はメモリとファイルの2か所にある。 消すときは history -d と history -w の両方
  • 共有設定や複数端末では、ファイルを先に消してから全端末で history -c; history -r。 zsh は fc -p で読み直す
  • パスワードは引数に書かず、打ってしまったら履歴の掃除に加えてパスワード自体を変更する

本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。

(記載例)出典:株式会社RJC「historyコマンドの使い方|Ctrl+R検索・履歴削除・HISTSIZE」

株式会社RJCでは、historyコマンドやシェルの設定の使い方を仲間と学び合っています。こうした知識を共有しながら、日々技術を磨いています。

株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。

WE ARE HIRING

RJCで一緒に開発しながら、
成長を楽しみませんか?

RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!

  • 127日年間休日
  • 12時間平均残業時間
  • 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!

ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。

ABOUT RJC RJCがどんな会社か知る 考え方、研修、働き方、福利厚生、社員の前職まで。RJCのことが丸わかり! RJC丸わかりページへ JOB DESCRIPTION 仕事内容・待遇を見てみる 仕事内容、給与・待遇、選考の流れ。経験者も未経験も!応募前に知りたいこと、まとめました! 募集要項を見る ENTRY エントリーする エントリーは1〜2分・履歴書不要です。まずは話を聞いてみたい、という方でも歓迎です! エントリーフォームへ

RJCで一緒に開発しながら、 成長を楽しみませんか?