Take the 2-minute tour ×
Super User is a question and answer site for computer enthusiasts and power users. It's 100% free, no registration required.

A little while ago I decided to log all my terminal activities by adding

script -t 0 "/Users/XXXXXXX/terminalLogs/log0$(date '+%y-%m-%d-%H:%M').txt"

to my .bash_profile file. This worked generally as expected, but I've found a problem with resizing windows.

So I start my terminal window as so:

enter image description here

All fine... if I then resize the window and open a file using vim I get:

enter image description here

(you'll notice the the vim window is smaller than the terminal window)

If I type 'exit' to exit the logging, and resize I get the vim terminal I was expecting.

enter image description here

So I'm a little confused and it would be great if people could either explain what's happening, or if they could suggest a mod, or if people have better ideas for how I should be logging commands. :(

share|improve this question
    
It would be interesting, if you have the same behaviour using another terminal application, like iTerm2. Have you tried this? –  cyphorious Mar 2 '12 at 13:36

2 Answers 2

up vote 3 down vote accepted

When you resize a terminal emulator’s window, it adjusts its pseudo terminal (“pty”) by making a TIOCSWINSZ (Terminal IO Control Set WINdow SiZe) ioctl system call. In turn, the kernel sends a SIGWINCH (WINdow CHange) signal to the foreground process group (e.g. the running instance of Vim) of that pty. Finally, the program(s) that received the SIGWINCH can use a TIOCGWINSZ (G for Get) ioctl to retrieve the new pty dimensions and redraw itself as appropriate.

Due to the way the script program works, the programs running “inside” the script session are actually running on a different pty from the pty created by the terminal emulator.

Consider this log:

% tty
/dev/ttys003
% script
Script started, output file is typescript
% tty
/dev/ttys004
% exit

Script done, output file is typescript

Initially, the shell is running on ttys003, but the shell that is started “inside” the script session is running on ttys004.

If I resized the terminal emulator window before exiting the script session, the terminal emulator would set the new size for ttys003, and the kernel would send a SIGWINCH to the script program (the foreground process of ttys003). Ideally, the script program would read the “outer” pty’s new dimensions and set the “inner” pty to have the same size. This would, in turn, cause the foreground process group of ttys004 (i.e. your Vim instance) to receive a SIGWINCH.

Unfortunately, the version of script you are using (Apple version’s from Lion?) does not appear to pass along the change in window size (and unhandled SIGWINCH is effectively ignored). Other versions (from util-linux-ng) appear to do a better job handling SIGWINCH, but they may not be readily compilable on your system.


If you can stand to manually trigger the adaptation to the new size, then you can simply run the resize command (/usr/X11/bin/resize) inside the “inner” pty. It will query the terminal emulator for the appropriate size using escape sequences and then set the pty to the correct dimensions. In your stated scenario, you could do :!resize from inside your Vim instance to resize the “inner” pty (which Vim will notice once the :! command has finished).

If you want automatic resizing to work, then you will have to find a version of script that properly propagates pty dimension changes (by handling SIGWINCH and making the proper ioctls). Alternatively, you might be able to replace your script invocation with an invocation of the following Expect program:

#!/usr/bin/expect
proc date {fmt} {
    clock format [clock seconds] -format $fmt
}
set file [if {$argc > 0} {lindex $argv 0} {list typescript}]

send_user "Script started, output file is $file\n"
log_file "$file"
send_log "Script started on [date %+]\n"

# WINCH code from http://ubuntuforums.org/showthread.php?t=865420
trap {
 set rows [stty rows]
 set cols [stty columns]
 stty rows $rows columns $cols < $spawn_out(slave,name)
} WINCH

spawn -noecho $env(SHELL)
interact

send_log "\nScript done on [date %+]\n"
log_file
send_user "Script done, output file is $file\n"

Give it a filename as its only argument:

 /path/to/script.expect "$HOME/terminalLogs/log0$(date '+%y-%m-%d-%H:%M').txt"
share|improve this answer
    
wow... that's quite the answer... :) –  Joe Mar 5 '12 at 17:14

I don't have a definitive answer but…

  • According to its man page ($ man script), script doesn't seem to like interactive programs:

Certain interactive commands, such as vi(1), create garbage in the typescript file. The script utility works best with commands that do not manipulate the screen. The results are meant to emulate a hardcopy terminal, not an addressable one.

  • The "default" size is the same as your window's size when you start script.

  • It's possible that script forcefully resets or disables a bunch of functions (like the ability to resize the window). The man page is silent about this subject but I think it would make sense to prevent resizing.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.