Documenting Unix commands on the command line
I would like to append both the last command and the output of the last command to a text file for the purpose of a tutorial.
For example: After I do an ls
in my home directory I see this on the screen
bguiz@sheen:~$ ls
Desktop Music Documents
I want to then be able to enter a single command which will append the following to a textfile named cmd.txt
$ ls
Desktop Music Documents
The idea is that each time I enter a command, I can log both the command itself and its output to the same file, and after several commands, it will demonstrate a particular series of commands. I know this can be done manually - but why do that if there's an easy alternative, right?
This is what I've cooked up so far:
echo -n "\$ " >> cmd.txt; echo !-1:p >> cmd.txt; !-1 >> cmd.txt
It works, but is rather clunky, and has several gotchas such as not being able to preserve the exact screen formatting.
Is the a more elegant solution?
Thank you for the answers so far, but I have a requiement that it needs to work with pipe, e.g.:
ls -lart | grep ^d
Needs to get this appended in the file:
$ ls -lart | grep ^d
drwx------ 14 bguiz staff 4096 2010-03-03 15:52 .cache
drwx------ 5 bguiz staff 4096 2010-03-03 09:38 .ssh
Solution 1:
[script.ksh] run with "script.ksh ls"
#!/bin/ksh
OUTPUT="cmd.txt"
if [[ $# -eq 0 ]];then
print "no command to run"
exit
fi
# dump command being run to file
echo $@ >> $OUTPUT
# run command and output stdout to the screen and file
$@ | tee -a $OUTPUT
Solution 2:
Rather simpler than the cleverness you've been trying:
$ script cmd.txt
do what you want to document here
then hit Control-d.
You can edit the file at a later date to add annotations if you wish, and you can use
$ script -a cmd.txt
to append more text to an existing file.
The available options seem to vary considerably between implementation.
- The Mac OS X (i.e. BSD) script supports
-k
which logs keyboard input to the command - The GNU version (found on linux systems) supports
-c
which allows you to specify the command on the original command line, allowing you to skip the "type your demonstration here then hit control-d" bit - The BSD version can also specify the command on the command line but does not accept a flag for that instead it must follow the output filename (which is required in this case).
Finally the GNU version warns the vi
is not well represented in type scripts (and I imagine that this warning applies equally well to all other commands that make use of curses).
Solution 3:
Write a script script.sh
like the following were you insert annotation in the form of comments:
#!/bin/sh -v
# Annotating the behaviour of the ls command
ls -l
# Other comments on the next command
cmd
Note the -v
switch in the first line:
-v verbose The shell writes its input to standard error as it is read.
Then execute the script redirecting both stdout and stderr to the file cmd.txt
using:
$ ./script.sh > cmd.txt 2>&1
The file cmd.txt
will contain the annotations, the commands and their relative output like:
# Annotating the behaviour of the ls command
ls -l
total 1824
drwxr-xr-x 11 mrucci mrucci 4096 2010-02-14 18:16 apps
drwxr-xr-x 2 mrucci mrucci 4096 2010-02-20 12:54 bin
-rw------- 1 mrucci mrucci 117469 2010-02-25 11:02 todo.txt
# Other comments on the next command
cmd
./testscript.sh: 7: cmd: not foun
PS: remember to give execution permission to the script with:
$ chmod +x script.sh
Solution 4:
In the circumstances, I generally use one of two techniques:
sh -x script
Or simply run the commands and then use copy'n'paste to save the material to a file.
The 'sh -x' output doesn't include the normal PS1 prompt - it uses the PS3 which defaults to '+ ', IIRC. And it slightly modifies the output - the details vary a bit depending on the shell you are using (so 'bash' does more messing than 'ksh' or Bourne shell do). I seldom need more material than copy'n'paste can manage, so it is my predominant modus operandi for StackOverflow and SuperUser, etc.