ターミナルでの作業内容をそのまま残したい

障害対応やサーバの初期構築では、実行したコマンドとその出力をあとから見返したい場面がある。ターミナルのスクロールバックをコピーする方法もあるが、バッファからあふれた分は失われる。teeコマンド で残せるのは個々のコマンドの出力だけで、入力したコマンド自体は残らない。

scriptコマンドを使うと、ターミナルに表示された内容をそのままファイルへ記録できる。util-linuxに含まれており、多くのディストリビューションで最初から利用できる。

$ script --version
script from util-linux 2.38.1

基本の使い方

scriptにログの出力先ファイルを指定して実行すると、記録用のシェルが起動する。以降の操作はすべてファイルに記録され、exitで記録を終了する。

$ script session.log
Script started, output log file is 'session.log'.
# whoami
root
# date
Wed Aug 12 13:56:00 UTC 2026
# exit
Script done.

記録されたファイルには、入力したコマンドと出力の両方が残る。

$ cat session.log
Script started on 2026-08-12 13:55:58+00:00 [TERM="xterm" TTY="/dev/pts/1" COLUMNS="-1" LINES="-1"]
# whoami
root
# date
Wed Aug 12 13:56:00 UTC 2026
# exit

Script done on 2026-08-12 13:56:02+00:00 [COMMAND_EXIT_CODE="0"]

先頭と末尾に、開始時刻・終了時刻と端末情報の行が自動で挿入される。

ファイル名を省略した場合は、カレントディレクトリのtypescriptに記録される。

特定のコマンドだけを記録する

-cオプションでコマンドを指定すると、対話シェルを起動せず、指定したコマンドの実行内容だけを記録する。

$ script -c "echo hello; whoami" out.log
Script started, output log file is 'out.log'.
hello
root
Script done.

-qオプションを併用すると、Script startedなどのメッセージを抑制できる。-q-cを組み合わせると、シェルスクリプトから呼び出しても余計な出力が混ざらない。

$ script -q -c "echo hello; whoami" out.log
hello
root

既存のログに追記する

デフォルトではログファイルを毎回上書きする。-aオプションをつけると既存ファイルの末尾へ追記する。

$ script -q -a -c "echo appended" out.log
appended

$ cat out.log
Script started on 2026-08-12 13:45:28+00:00 [COMMAND="echo hello; whoami" TERM="xterm" TTY="/dev/pts/0" COLUMNS="-1" LINES="-1"]
hello
root

Script done on 2026-08-12 13:45:28+00:00 [COMMAND_EXIT_CODE="0"]
Script started on 2026-08-12 13:45:29+00:00 [COMMAND="echo appended" TERM="xterm" TTY="/dev/pts/0" COLUMNS="-1" LINES="-1"]
appended

Script done on 2026-08-12 13:45:29+00:00 [COMMAND_EXIT_CODE="0"]

記録中のログを別の端末から追う

scriptはログをバッファリングするため、記録の途中ではファイルに内容が反映されない。-fオプションをつけると出力のたびにファイルへ書き出す。

$ script -q -f -c "echo start; sleep 3; echo end" flush.log

記録中に別の端末からtail -fで開くと、作業の進行をそのまま追える。長時間の作業を記録しながら、別の端末で経過を確認する場合に使う。

$ tail -f flush.log

終了ステータスを引き継ぐ

scriptの終了ステータスは、デフォルトでは記録したコマンドの成否と無関係に0になる。CIやシェルスクリプトから呼び出す場合は-eオプションを使い、記録対象のコマンドの終了ステータスをそのまま返す。

$ script -q -c "exit 3" e.log; echo "exit status: $?"
exit status: 0

$ script -q -e -c "exit 3" e.log; echo "exit status: $?"
exit status: 3

エスケープシーケンスを取り除く

scriptは端末に送られたバイト列をそのまま記録するため、色付きの出力ではANSIエスケープシーケンスもログに残る。cat -vで制御文字を可視化すると、色を指定する^[[01;34mのようなエスケープシーケンスと、行末のキャリッジリターン^Mを確認できる。

$ script -q -c "ls --color=always /" color.log
$ cat -v color.log
Script started on 2026-08-12 13:56:02+00:00 [COMMAND="ls --color=always /" TERM="xterm" TTY="/dev/pts/0" COLUMNS="-1" LINES="-1"]
^[[0m^[[01;36mbin^[[0m   ^[[01;34mdev^[[0m  ^[[01;34mhome^[[0m  ^[[01;34mmedia^[[0m  ^[[01;34mopt^[[0m   ^[[01;34mroot^[[0m  ^[[01;36msbin^[[0m  ^[[01;34msys^[[0m  ^[[01;34musr^[[0m^M
^[[01;34mboot^[[0m  ^[[01;34metc^[[0m  ^[[01;36mlib^[[0m   ^[[01;34mmnt^[[0m    ^[[01;34mproc^[[0m  ^[[01;34mrun^[[0m   ^[[01;34msrv^[[0m   ^[[30;42mtmp^[[0m  ^[[01;34mvar^[[0m^M

Script done on 2026-08-12 13:56:02+00:00 [COMMAND_EXIT_CODE="0"]

less -Rのようにエスケープシーケンスを解釈できるページャで開けばそのまま読める。テキストとして扱いたい場合は、sedで色の指定と行末の\rを取り除く。

$ sed -e 's/\x1b\[[0-9;]*m//g' -e 's/\r$//' color.log
Script started on 2026-08-12 13:56:02+00:00 [COMMAND="ls --color=always /" TERM="xterm" TTY="/dev/pts/0" COLUMNS="-1" LINES="-1"]
bin   dev  home  media  opt   root  sbin  sys  usr
boot  etc  lib   mnt    proc  run   srv   tmp  var

Script done on 2026-08-12 13:56:02+00:00 [COMMAND_EXIT_CODE="0"]

\x1bはGNU sedの拡張であり、macOSのBSD sedでは動作しない。また上記のsedが取り除くのは色の指定のみである。clearviが出力する画面消去の^[[H^[[2Jのように、m以外で終わるエスケープシーケンスは残る。

操作を再生する

--log-timingでタイミング情報を別ファイルに出力すると、記録した操作を実時間どおりに再生できる。出力の記録先は--log-outで指定する。

$ script -q --log-timing time.log --log-out typescript -c "echo first; sleep 10; echo second"
first
second

--log-outだけを記録した場合、タイミングファイルには直前の出力からの経過秒数と出力バイト数が並ぶ。

$ cat time.log
0.000247 7
10.006125 8

再生にはscriptreplayを使う。sleep 10の待ち時間も含めて、記録時と同じ間隔で出力を再現する。

$ scriptreplay --log-timing time.log --log-out typescript

--divisorで再生速度を変更できる。以下は10倍速で再生する例である。

$ scriptreplay --log-timing time.log --log-out typescript --divisor 10

長時間の待ち時間を含む記録では、--maxdelayで1回あたりの待ち時間の上限を秒で指定する。以下の例では10秒の待ち時間が2秒に短縮され、再生は約2秒で終わる。

$ scriptreplay --log-timing time.log --log-out typescript --maxdelay 2

記録時の注意点

viのように画面を書き換えるコマンドは、カーソル移動や再描画の制御文字がそのまま記録されるため、ログが読みづらくなる。scriptは画面への出力をそのまま残す。実行したコマンドの履歴を整理して残す用途には向かない。

ログイン時に自動で記録を始めたい場合は、ログインシェルだけが読み込む.profileに記述する。scriptが起動する内側のシェルは非ログインシェルであり、.profileを読み返さないため無限ループを避けられる。test -t 0は、scpssh host commandのように端末を持たない接続でscriptが起動し、セッションがハングするのを防ぐ。

if test -t 0 ; then
    script
    exit
fi

また、scriptは端末に表示された内容をすべて記録するため、コマンドライン引数に書いたトークンやパスワードもそのまま残る。ログを共有する前に内容を確認する。

参考

» script(1) - Debian Manpages

» scriptreplay(1) - Debian Manpages