7

When using Ctrl+R to search bash history, is there some way to match two words that aren't next to each other. For example, let's say I wanted to find the last command that contained httpd and awk but not next to each other. Is there some better option than resorting to grepping the bash history to match both or pressing Ctrl+R to cycle through entries matching one keyword until the desired command is found?

3

Bash Reference Manual says:

Readline provides commands for searching through the command history for lines containing a specified string

You want a regexp instead of fixed string.

Try hstr:
1. Installation
2. Configuration

You should see something like this with hstr:
enter image description here

Update:
Another tool is fzf.

  1. Install: git clone --depth 1 https://github.com/junegunn/fzf.git ~/.fzf && ~/.fzf/install

  2. Re-source your ~/.bashrc: source ~/.bashrc

You should see something like this with fzf: enter image description here

2

I dont know of any built-in way to do this, but you can write a small function to do the grep and edit your history file so that the results appear at the end, and you can then easily choose one of the matches by just moving up through the new history. (This does change the order of commands in your history).

Here's such a function. I'm assuming you want to find the 2 (or more) words no matter which order they appear in. You can set the max number of matches you want to accept; here it is 10. I'm also assuming that the initial grep doesnt return a humungous string, or you'll need to use temporary files instead of bash strings.

hist(){
    local maxmatches=10 word=$1 matches new nummatches
    shift
    history -w # write out history to HISTFILE
    matches=$(grep -e "$word" $HISTFILE)
    for word
    do   new=$(echo "$matches" | grep -e "$word")  || return # if str too big
         matches=$new
    done
    nummatches=$(echo "$matches" | wc -l)
    echo "$nummatches matches"
    if [ $nummatches -gt 0 -a $nummatches -le $maxmatches ]
    then echo "$matches" >>$HISTFILE # add matches to end of file
         history -c # clear history
         history -r # read history from file
         history $nummatches # show last few lines
    else echo "zero or too many matches. (max $maxmatches)"
    fi
}

If you dont want regexp pattern matching for your words, use fgrep instead of grep. If you want only the given order, use a single word like "httpd.*awk". You could also remove the for loop if only using one word in this way.

  • Not exactly what I was hoping for, but I'll give it +1 for creativity – sa289 Jun 15 '15 at 16:34

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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