2012/8/17 郑文辉(Techlive Zheng) <techlivezh...@gmail.com>: > 2012/8/17 郑文辉(Techlive Zheng) <techlivezh...@gmail.com>: >> 2012/8/17 Chet Ramey <chet.ra...@case.edu>: >>> On 8/16/12 10:11 PM, 郑文辉(Techlive Zheng) wrote: >>>> 2012/8/17 Chet Ramey <chet.ra...@case.edu>: >>>>> On 8/16/12 9:17 AM, 郑文辉(Techlive Zheng) wrote: >>>>>> I was trying to reload the bash history file which changed by another >>>>>> bash session with the following commands, but it wouldn't work, please >>>>>> help me, why? >>>>>> >>>>>> ``` >>>>>> new_history=$(history -a /dev/stdout) >>>>>> history -c >>>>>> history -r >>>>>> echo "$new_history" | history -r /dev/stdin >>>>>> ``` >>>>> >>>>> One possible cause that springs to mind is the fact that the `history -r' >>>>> at the end of the pipeline is run in a subshell and cannot affect its >>>>> parent's history list. >>>> >>>> So, How could I accomplish this kind of thing? >>> >>> Why not just use a regular file? >>> >>> -- >>> ``The lyf so short, the craft so long to lerne.'' - Chaucer >>> ``Ars longa, vita brevis'' - Hippocrates >>> Chet Ramey, ITS, CWRU c...@case.edu http://cnswww.cns.cwru.edu/~chet/ >> >> Actually, I was tring to erase duplicate entries and share history >> across bash sessions.'erasedups' in `HISTCONTROL` only have effect for >> history list in the memory, so my solution is to load entire history >> file into memory and save it after every command finished. >> >> Here is what I am currently have in .bashrc, and it works as expected. >> >> reload_history() { >> local HISTHASH_NEW=`md5sum $HOME/.bash_history | cut -d' ' -f1` >> if [ "$HISTHASH" = "$HISTHASH_NEW" ]; then >> history -w >> # This is necessay because we need >> # to clear the last append signture >> history -c >> history -r >> else >> HISTTEMP=`mktemp` >> history -a $HISTTEMP >> history -c >> history -r >> history -r $HISTTEMP >> history -w >> rm $HISTTEMP >> fi >> HISTHASH=`md5sum $HOME/.bash_history | cut -d' ' -f1` >> } >> >> export PROMPT_COMMAND="reload_history;$PROMPT_COMMAND" >> >> Considering `mkemp` then remove the temp file on every prompt command >> is a little bit expensive, I want to directly pipe the output of the >> `history -a` to `hisotory -r` like below, unfortunately, this wouldn't >> work, because `history -r` could not handle /dev/stdin. >> >> reload_history() { >> local HISTHASH_NEW=`md5sum $HOME/.bash_history | cut -d' ' -f1` >> if [ "$HISTHASH" = "$HISTHASH_NEW" ]; then >> history -w >> # This is necessay because we need >> # to clear the last append signture >> history -c >> history -r >> else >> new_history=$(history -a /dev/stdout) >> history -c >> history -r >> echo "$new_history" | history -r /dev/stdin >> history -w >> fi >> HISTHASH=`md5sum $HOME/.bash_history | cut -d' ' -f1` >> } >> >> export PROMPT_COMMAND="reload_history;$PROMPT_COMMAND" > > I have just checked out the source of bash and found that `read()` or > `mmap` is used to read the history file as below. The following code > could not handle /dev/stdin properly. As I am not a C expert, I could > not come up a patch for this, maybe someone here could give me a > little help? > > From lib/readline/histfile.c:200 > > #ifdef HISTORY_USE_MMAP > /* We map read/write and private so we can change newlines to NULs without > affecting the underlying object. */ > buffer = (char *)mmap (0, file_size, PROT_READ|PROT_WRITE, > MAP_RFLAGS, file, 0); > if ((void *)buffer == MAP_FAILED) > { > errno = overflow_errno; > goto error_and_exit; > } > chars_read = file_size; > #else > buffer = (char *)malloc (file_size + 1); > if (buffer == 0) > { > errno = overflow_errno; > goto error_and_exit; > } > > chars_read = read (file, buffer, file_size); > #endif
I have tried using a named pipe or process substition, neither worked.