linux - Use a separate history for 'read -e' (readline)

06
2014-04
  • BenjiWiebe

    I would like to write an interactive command shell in shell script, for easier adjusting of the iptables firewall. The problem is, that read -e uses the shell history. Is there a way of using a separate history for read -e in a script?

  • Answers
  • rici

    If you have rlwrap (debian package rlwrap), then you could use something like:

    LINE=$(rlwrap head -n1)
    

    which will use the file ~/.head_history by default. (man rlwrap for more details, including options for specifying a history filename.)

    Another possibility is to run read in a subshell with HISTFILE set to your own history file, but you'll need to do a lot more work because although read -e uses the history, it does not update it. So you'll probably need something like:

    LINE=$(bash -c 'HISTFILE=/path/to/history_file;
                    history -r; read -e LINE;
                    history -s "$LINE"; history -w;
                    echo "$LINE")
    

  • Related Question

    PowerShell: history enhancements (readline)?
  • IttayD

    Some of the things I like in Bash and would love to know how to do in PowerShell:

    1. In Bash, I have history scrolling set up so that it only scrolls commands that begin with the same prefix as the current line. If I want to see my latest commit (e.g. to reuse part of the comment) I write 'git' and then .

    2. Related is of course the history search with Ctrl + R

    3. To find other things, I write:

      h | grep foo
      

      In PowerShell I use:

      h -c 1000 | where {$_.commandline.contains("foo")}
      

      (obviously I'm a newbie, there must be a shorter way)

    4. Things like:

      mv file.txt{,.bak}
      

      or

      mv file.txt !#$.bak
      
    5. Magic space (that expands !$ inline)

    What are the alternatives in PowerShell?


  • Related Answers
  • njd

    For (3), you can write it as a function in your profile (e.g. %USERPROFILE%\My Documents\WindowsPowerShell\profile.ps1):

    function hh ([string] $word) {
        Get-History -c 1000 | where {$_.commandline.contains($word)}
    }
    

    Then:

    hh foo
    

    But Powershell is best thought of as a scripting language than as an interactive shell, because the underlying console is still cmd.exe with all its limitations.

    So it's F7 for interactive history, F3 to copy the previous command, F1 to copy a single character, F2 to copy the previous command up to a particular character, etc, etc.

  • Rynant

    1 - You can use F8 from the windows console to cycle through commands that match the beginning of the current line. This is a case sensitive match.

    2 - You can use # to match previous commands. Using #<partial match><tab> is case insensitive and will match text at any position in the previous commands.

    If you have the following command history:

    # 1
    $np = Start-Process notepad -PassThru
    # 2
    $np| get-process
    # 3
    $np| Stop-Process
    

    Typing #pr then tab repeatedly will cycle through 1, 2 and 3.

    Typing #st then tab repeatedly will cycle through 1 and 3.

    Using only # will match all history.

    # can also be used after entering part of a command. If your history is:

    'notepad'
    select *
    

    You can type Get-Process #n<tab>| #s<tab> to get Get-Process 'notepad'| select *

    3 - You can use Select-String. Create an alias for it to make it easy to use (PowerShell v3 added the alias sls). You could then do.

    h| sls foo
    

    4 - You can do something like:

    gci *a.txt| ren -n {$_.Name + '.bak'}
    

    5 - $$ matches the last token of the last command, but I don't know of a way to expand it inline.

  • Joe Carroll

    You should check out Oisin Grehan's PSReadline module: http://nivot.org/blog/post/2012/09/12/Emulating-Bash-GNU-Readline-with-PowerShell-30

    The code is available here: https://bitbucket.org/oising/psreadline/overview

    This makes PowerShell actually usable as a CLI, from the point of view of experienced *nix admins who occasionally work with Windows, by adding basic EMACS bindings for line editing, history search etc.