Search code examples
linuxshelltcsh

tcsh, save command in a history, only if the command was successful


I'm new to tcsh so please advice me. Now I use postcmd variable to save history:

alias postcmd "history -S; history -M;"

The problem is, it saves almost everything I type to terminal. I want to filter out some misspelled commands, or, for example, commands that returned some non-zero status. My first try is this:

alias postcmd "if ($? == 0) history -S; history -M;"

But the above, still saves all misspelled commands and commands with non-zero exit status. The question is, how to make tcsh to filter out as much unappropriate commands as possible?

* update *

I have no clue how to make tcsh history to behave as I want it to, so I leave a note for myself here. What I did is

set history = 0

And that's it.


Solution

  • set savehist = (3000 merge lock)
    alias precmd 'if($? == 0) history -S; history -c; history -M'
    

    then

    tcsh% true
    tcsh% false
    tcsh% false
    tcsh% true
    tcsh% history
        20  0:15    true
        21  0:16    true
        22  0:16    history
    

    Why the history -c?

    It clears the history; otherwise failing / misspelled commands will still be added to the current (in-memory) history, and a subsequent history -S will save them, even if only invoked after a successful command.

    Notice that in if(..) cmd1; cmd2; cmd3 cmd2 and cmd3 will be run unconditionally.

    Why precmd instead of postcmd?

    tcsh% alias postcmd 'echo postcmd = $?'
    tcsh% alias precmd 'echo precmd = $?'
    postcmd = 0
    precmd = 0
    tcsh% false
    postcmd = 0
    precmd = 1
    

    Does an intermediate alias work to group the commands?

    No, because the command after if (...) can't be an alias:

    tcsh% alias ok 'echo ok'
    tcsh% ok
    ok
    tcsh% if (1) ok
    ok: Command not found.
    

    From the tcsh(1) manpage:

    if (expr) command

    ... command must be a simple command, not an alias, a pipeline, a command list or a parenthesized command list, but it may have arguments

    Why not use a multiline alias with precmd or postcmd?

    Because it will invoke itself recursively:

    tcsh% alias postcmd 'if ($? == 0) then\
    echo OK\
    endif\
    '
    OK
    OK
    <ad nauseam>
    ^C